• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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