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