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_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 panda::mem { 25 26 /** 27 * Base barrier set 28 */ 29 class GCBarrierSet { 30 public: 31 GCBarrierSet() = delete; GCBarrierSet(mem::InternalAllocatorPtr allocator,BarrierType pre_type,BarrierType post_type)32 GCBarrierSet(mem::InternalAllocatorPtr allocator, BarrierType pre_type, BarrierType post_type) 33 : pre_type_(pre_type), 34 post_type_(post_type), 35 pre_operands_(allocator->Adapter()), 36 post_operands_(allocator->Adapter()) 37 { 38 } 39 40 NO_COPY_SEMANTIC(GCBarrierSet); 41 NO_MOVE_SEMANTIC(GCBarrierSet); 42 virtual ~GCBarrierSet() = 0; 43 GetPreType()44 BarrierType GetPreType() const 45 { 46 ASSERT(IsPreBarrier(pre_type_)); 47 return pre_type_; 48 } 49 GetPostType()50 BarrierType GetPostType() const 51 { 52 ASSERT(IsPostBarrier(post_type_)); 53 return post_type_; 54 } 55 IsPreBarrierEnabled()56 virtual bool IsPreBarrierEnabled() 57 { 58 return !mem::IsEmptyBarrier(pre_type_); 59 } 60 61 /** 62 * Pre barrier. Used by interpreter. 63 * @param pre_val_addr - reference currently(before store/load happened) stored in the field 64 */ 65 virtual void PreBarrier(void *pre_val_addr) = 0; 66 67 /** 68 * Post barrier. Used by interpeter. 69 * @param obj_addr - address of field where we store 70 * @param val_addr - reference stored into or loaded from the field 71 */ 72 virtual void PostBarrier(const void *obj_addr, void *val_addr) = 0; 73 74 /** 75 * Post barrier for array write. Used by interpeter. 76 * @param obj_addr - address of the array object 77 * @param size - size of the array object 78 */ 79 virtual void PostBarrierArrayWrite(const void *obj_addr, size_t size) = 0; 80 81 /** 82 * Post barrier for writing in every field of an object. Used by interpeter. 83 * @param object_addr - address of the object 84 * @param size - size of the object 85 */ 86 virtual void PostBarrierEveryObjectFieldWrite(const void *obj_addr, size_t size) = 0; 87 88 /** 89 * Get barrier operand (literal, function pointer, address etc. See enum BarrierType for details. 90 * Should be used for barrier generation in Compiler. 91 * @param name - string with name of operand 92 * @return barrier operand (value is address or literal) 93 */ 94 BarrierOperand GetBarrierOperand(BarrierPosition barrier_position, std::string_view name); 95 96 BarrierOperand GetPostBarrierOperand(std::string_view name); 97 98 protected: 99 /** 100 * Add barrier operand if there are no operands with this name 101 * @param barrier_position - pre or post position of barrier with added operand 102 * @param name - name of operand 103 * @param barrier_operand - operand 104 */ AddBarrierOperand(BarrierPosition barrier_position,std::string_view name,const BarrierOperand & barrier_operand)105 void AddBarrierOperand(BarrierPosition barrier_position, std::string_view name, 106 const BarrierOperand &barrier_operand) 107 { 108 if (barrier_position == BarrierPosition::BARRIER_POSITION_PRE) { 109 ASSERT(pre_operands_.find(name) == pre_operands_.end()); 110 pre_operands_.insert({name.data(), barrier_operand}); 111 } else { 112 ASSERT(barrier_position == BarrierPosition::BARRIER_POSITION_POST); 113 ASSERT(post_operands_.find(name) == post_operands_.end()); 114 post_operands_.insert({name.data(), barrier_operand}); 115 } 116 } 117 118 private: 119 BarrierType pre_type_; // Type of PRE barrier. 120 BarrierType post_type_; // Type of POST barrier. 121 PandaMap<PandaString, BarrierOperand> pre_operands_; 122 PandaMap<PandaString, BarrierOperand> post_operands_; 123 }; 124 125 /** 126 * BarrierSet with barriers do nothing 127 */ 128 class GCDummyBarrierSet : public GCBarrierSet { 129 public: GCDummyBarrierSet(mem::InternalAllocatorPtr allocator)130 explicit GCDummyBarrierSet(mem::InternalAllocatorPtr allocator) 131 : GCBarrierSet(allocator, BarrierType::PRE_WRB_NONE, BarrierType::POST_WRB_NONE) 132 { 133 } 134 135 NO_COPY_SEMANTIC(GCDummyBarrierSet); 136 NO_MOVE_SEMANTIC(GCDummyBarrierSet); 137 ~GCDummyBarrierSet() override = default; 138 PreBarrier(void * pre_val_addr)139 void PreBarrier([[maybe_unused]] void *pre_val_addr) override {} 140 PostBarrier(const void * obj_addr,void * stored_val_addr)141 void PostBarrier([[maybe_unused]] const void *obj_addr, [[maybe_unused]] void *stored_val_addr) override {} 142 PostBarrierArrayWrite(const void * obj_addr,size_t size)143 void PostBarrierArrayWrite([[maybe_unused]] const void *obj_addr, [[maybe_unused]] size_t size) override {} 144 PostBarrierEveryObjectFieldWrite(const void * obj_addr,size_t size)145 void PostBarrierEveryObjectFieldWrite([[maybe_unused]] const void *obj_addr, [[maybe_unused]] size_t size) override 146 { 147 } 148 }; 149 150 class GCGenBarrierSet : public GCBarrierSet { 151 public: GCGenBarrierSet(mem::InternalAllocatorPtr allocator,void * min_addr,CardTable * card_table,uint8_t card_bits,uint8_t dirty_card_value)152 GCGenBarrierSet(mem::InternalAllocatorPtr allocator, 153 /* POST ARGS: */ 154 void *min_addr, CardTable *card_table, uint8_t card_bits, uint8_t dirty_card_value) 155 : GCBarrierSet(allocator, BarrierType::PRE_WRB_NONE, BarrierType::POST_INTERGENERATIONAL_BARRIER), 156 min_addr_(min_addr), 157 card_table_addr_(reinterpret_cast<uint8_t *>(*card_table->begin())), 158 card_bits_(card_bits), 159 dirty_card_value_(dirty_card_value), 160 card_table_(card_table) 161 { 162 // POST 163 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "MIN_ADDR", 164 BarrierOperand(BarrierOperandType::ADDRESS, BarrierOperandValue(min_addr))); 165 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "CARD_TABLE_ADDR", 166 BarrierOperand(BarrierOperandType::UINT8_ADDRESS, BarrierOperandValue(card_table_addr_))); 167 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "CARD_BITS", 168 BarrierOperand(BarrierOperandType::UINT8_LITERAL, BarrierOperandValue(card_bits))); 169 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "DIRTY_VAL", 170 BarrierOperand(BarrierOperandType::UINT8_LITERAL, BarrierOperandValue(dirty_card_value))); 171 } 172 173 void PreBarrier(void *pre_val_addr) override; 174 175 void PostBarrier(const void *obj_addr, void *stored_val_addr) override; 176 177 void PostBarrierArrayWrite(const void *obj_addr, size_t size) override; 178 179 void PostBarrierEveryObjectFieldWrite(const void *obj_addr, size_t size) override; 180 181 ~GCGenBarrierSet() override = default; 182 183 NO_COPY_SEMANTIC(GCGenBarrierSet); 184 NO_MOVE_SEMANTIC(GCGenBarrierSet); 185 186 private: 187 // Store operands explicitly for interpreter perf 188 // POST BARRIER 189 void *min_addr_ {nullptr}; //! Minimal address used by VM. Used as a base for card index calculation 190 uint8_t *card_table_addr_ {nullptr}; //! Address of card table 191 uint8_t card_bits_ {0}; //! how many bits encoded by card (i.e. size covered by card = 2^card_bits_) 192 uint8_t dirty_card_value_ {0}; //! value of dirty card 193 FIELD_UNUSED CardTable *card_table_ {nullptr}; 194 }; 195 196 class GCG1BarrierSet : public GCBarrierSet { 197 public: 198 using ThreadLocalCardQueues = PandaVector<CardTable::CardPtr>; 199 static constexpr size_t G1_POST_BARRIER_RING_BUFFER_SIZE = 1024 * 8; 200 using G1PostBarrierRingBufferType = mem::LockFreeBuffer<mem::CardTable::CardPtr, G1_POST_BARRIER_RING_BUFFER_SIZE>; 201 GCG1BarrierSet(mem::InternalAllocatorPtr allocator,std::atomic<bool> * concurrent_marking_flag,objRefProcessFunc pre_store_func,objTwoRefProcessFunc post_func,uint8_t region_size_bits_count,CardTable * card_table,ThreadLocalCardQueues * updated_refs_queue,os::memory::Mutex * queue_lock)202 GCG1BarrierSet(mem::InternalAllocatorPtr allocator, 203 // PRE ARGS: 204 std::atomic<bool> *concurrent_marking_flag, objRefProcessFunc pre_store_func, 205 // POST ARGS: 206 objTwoRefProcessFunc post_func, uint8_t region_size_bits_count, CardTable *card_table, 207 ThreadLocalCardQueues *updated_refs_queue, os::memory::Mutex *queue_lock) 208 : GCBarrierSet(allocator, BarrierType::PRE_SATB_BARRIER, BarrierType::POST_INTERREGION_BARRIER), 209 concurrent_marking_flag_(concurrent_marking_flag), 210 pre_store_func_(pre_store_func), 211 post_func_(post_func), 212 region_size_bits_count_(region_size_bits_count), 213 card_table_(card_table), 214 min_addr_(ToVoidPtr(card_table->GetMinAddress())), 215 updated_refs_queue_(updated_refs_queue), 216 queue_lock_(queue_lock) 217 { 218 ASSERT(pre_store_func_ != nullptr); 219 ASSERT(post_func_ != nullptr); 220 // PRE 221 AddBarrierOperand( 222 BarrierPosition::BARRIER_POSITION_PRE, "CONCURRENT_MARKING_ADDR", 223 BarrierOperand(BarrierOperandType::BOOL_ADDRESS, BarrierOperandValue(concurrent_marking_flag))); 224 AddBarrierOperand( 225 BarrierPosition::BARRIER_POSITION_PRE, "STORE_IN_BUFF_TO_MARK_FUNC", 226 BarrierOperand(BarrierOperandType::FUNC_WITH_OBJ_REF_ADDRESS, BarrierOperandValue(pre_store_func_))); 227 // POST 228 AddBarrierOperand( 229 BarrierPosition::BARRIER_POSITION_POST, "REGION_SIZE_BITS", 230 BarrierOperand(BarrierOperandType::UINT8_LITERAL, BarrierOperandValue(region_size_bits_count_))); 231 AddBarrierOperand( 232 BarrierPosition::BARRIER_POSITION_POST, "UPDATE_CARD_FUNC", 233 BarrierOperand(BarrierOperandType::FUNC_WITH_TWO_OBJ_REF_ADDRESSES, BarrierOperandValue(post_func_))); 234 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "CARD_TABLE_ADDR", 235 BarrierOperand(BarrierOperandType::UINT8_ADDRESS, 236 BarrierOperandValue(reinterpret_cast<uint8_t *>(*card_table->begin())))); 237 AddBarrierOperand(BarrierPosition::BARRIER_POSITION_POST, "MIN_ADDR", 238 BarrierOperand(BarrierOperandType::ADDRESS, BarrierOperandValue(min_addr_))); 239 } 240 241 bool IsPreBarrierEnabled() override; 242 243 void PreBarrier(void *pre_val_addr) override; 244 245 void PostBarrier(const void *obj_addr, void *stored_val_addr) override; 246 247 void PostBarrierArrayWrite(const void *obj_addr, size_t size) override; 248 249 void PostBarrierEveryObjectFieldWrite(const void *obj_addr, size_t size) override; 250 251 ~GCG1BarrierSet() override = default; 252 GetCardTable()253 CardTable *GetCardTable() const 254 { 255 return card_table_; 256 } 257 GetUpdatedRefsQueue()258 ThreadLocalCardQueues *GetUpdatedRefsQueue() const 259 { 260 return updated_refs_queue_; 261 } 262 GetQueueLock()263 os::memory::Mutex *GetQueueLock() const 264 { 265 return queue_lock_; 266 } 267 268 NO_COPY_SEMANTIC(GCG1BarrierSet); 269 NO_MOVE_SEMANTIC(GCG1BarrierSet); 270 271 private: 272 using PostFuncT = std::function<void(const void *, const void *)> *; 273 // Store operands explicitly for interpreter perf 274 // PRE BARRIER 275 std::atomic<bool> *concurrent_marking_flag_ {nullptr}; 276 objRefProcessFunc pre_store_func_ {nullptr}; 277 // POST BARRIER 278 objTwoRefProcessFunc post_func_; //! function which is called for the post barrier if all conditions 279 uint8_t region_size_bits_count_ {0}; //! how much bits needed for the region 280 CardTable *card_table_ {nullptr}; //! 281 void *min_addr_ {nullptr}; //! Minimal address used by VM. Used as a base for card index calculation 282 ThreadLocalCardQueues *updated_refs_queue_; 283 os::memory::Mutex *queue_lock_; 284 }; 285 286 } // namespace panda::mem 287 288 #endif // PANDA_GC_BARRIER_H 289