1b1994897Sopenharmony_ci/** 2b1994897Sopenharmony_ci * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License. 5b1994897Sopenharmony_ci * You may obtain a copy of the License at 6b1994897Sopenharmony_ci * 7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8b1994897Sopenharmony_ci * 9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and 13b1994897Sopenharmony_ci * limitations under the License. 14b1994897Sopenharmony_ci */ 15b1994897Sopenharmony_ci 16b1994897Sopenharmony_ci#ifndef LIBPANDABASE_MEM_GC_BARRIER_H 17b1994897Sopenharmony_ci#define LIBPANDABASE_MEM_GC_BARRIER_H 18b1994897Sopenharmony_ci 19b1994897Sopenharmony_ci#include "utils/bit_field.h" 20b1994897Sopenharmony_ci 21b1994897Sopenharmony_ci#include <atomic> 22b1994897Sopenharmony_ci#include <cstdint> 23b1994897Sopenharmony_ci#include <functional> 24b1994897Sopenharmony_ci#include <variant> 25b1994897Sopenharmony_ci 26b1994897Sopenharmony_cinamespace panda::mem { 27b1994897Sopenharmony_ci 28b1994897Sopenharmony_ci/** 29b1994897Sopenharmony_ci * Represents Pre and Post barrier 30b1994897Sopenharmony_ci */ 31b1994897Sopenharmony_cienum BarrierPosition : uint8_t { 32b1994897Sopenharmony_ci BARRIER_POSITION_PRE = 0x1, // Should be inserted before each store/load when reference stored/loaded 33b1994897Sopenharmony_ci BARRIER_POSITION_POST = 0x0, // Should be inserted after each store/load when reference stored/loaded 34b1994897Sopenharmony_ci}; 35b1994897Sopenharmony_ci 36b1994897Sopenharmony_ci/** 37b1994897Sopenharmony_ci * Indicates if barrier for store or load 38b1994897Sopenharmony_ci */ 39b1994897Sopenharmony_cienum BarrierActionType : uint8_t { 40b1994897Sopenharmony_ci WRITE_BARRIER = 0x1, // Should be used around store 41b1994897Sopenharmony_ci READ_BARRIER = 0x0, // Should be used around load 42b1994897Sopenharmony_ci}; 43b1994897Sopenharmony_ci 44b1994897Sopenharmony_cinamespace internal { 45b1994897Sopenharmony_ciconstexpr uint8_t BARRIER_POS_OFFSET = 0U; // offset in bits for encoding position of barrier(pre or post) 46b1994897Sopenharmony_ciconstexpr uint8_t BARRIER_WRB_FLAG_OFFSET = 1U; // offset in bits for WRB flag 47b1994897Sopenharmony_ci} // namespace internal 48b1994897Sopenharmony_ci 49b1994897Sopenharmony_ciconstexpr uint8_t EncodeBarrierType(uint8_t value, BarrierPosition position, BarrierActionType action_type) 50b1994897Sopenharmony_ci{ 51b1994897Sopenharmony_ci // NOLINTNEXTLINE(hicpp-signed-bitwise) 52b1994897Sopenharmony_ci return (value << 2U) | (position << internal::BARRIER_POS_OFFSET) | 53b1994897Sopenharmony_ci (action_type << internal::BARRIER_WRB_FLAG_OFFSET); 54b1994897Sopenharmony_ci} 55b1994897Sopenharmony_ci 56b1994897Sopenharmony_ci/** 57b1994897Sopenharmony_ci * Should help to encode barrier for the compiler. 58b1994897Sopenharmony_ci * PreWrite barrier can be used for avoiding lost object problem. 59b1994897Sopenharmony_ci * PostWrite barrier used for tracking intergenerational or interregion references 60b1994897Sopenharmony_ci */ 61b1994897Sopenharmony_cienum BarrierType : uint8_t { 62b1994897Sopenharmony_ci PRE_WRB_NONE = EncodeBarrierType(1U, BarrierPosition::BARRIER_POSITION_PRE, BarrierActionType::WRITE_BARRIER), 63b1994897Sopenharmony_ci PRE_RB_NONE = EncodeBarrierType(1U, BarrierPosition::BARRIER_POSITION_PRE, BarrierActionType::READ_BARRIER), 64b1994897Sopenharmony_ci POST_WRB_NONE = EncodeBarrierType(1U, BarrierPosition::BARRIER_POSITION_POST, BarrierActionType::WRITE_BARRIER), 65b1994897Sopenharmony_ci POST_RB_NONE = EncodeBarrierType(1U, BarrierPosition::BARRIER_POSITION_POST, BarrierActionType::READ_BARRIER), 66b1994897Sopenharmony_ci /** 67b1994897Sopenharmony_ci * Pre barrier for SATB. 68b1994897Sopenharmony_ci * Pseudocode: 69b1994897Sopenharmony_ci * load CONCURRENT_MARKING_ADDR -> concurrent_marking 70b1994897Sopenharmony_ci * if (UNLIKELY(concurrent_marking)) { 71b1994897Sopenharmony_ci * load obj.field -> pre_val // note: if store volatile - we need to have volatile load here 72b1994897Sopenharmony_ci * if (pre_val != nullptr) { 73b1994897Sopenharmony_ci * call STORE_IN_BUFF_TO_MARK_FUNC(pre_val); 74b1994897Sopenharmony_ci * } 75b1994897Sopenharmony_ci * } 76b1994897Sopenharmony_ci * store obj.field <- new_val // STORE for which barrier generated 77b1994897Sopenharmony_ci * 78b1994897Sopenharmony_ci * Runtime should provide these parameters: 79b1994897Sopenharmony_ci * CONCURRENT_MARKING_ADDR - address of bool flag which indicates that we have concurrent marking on 80b1994897Sopenharmony_ci * STORE_IN_BUFF_TO_MARK_FUNC - address of function to store replaced reference 81b1994897Sopenharmony_ci */ 82b1994897Sopenharmony_ci PRE_SATB_BARRIER = EncodeBarrierType(2U, BarrierPosition::BARRIER_POSITION_PRE, BarrierActionType::WRITE_BARRIER), 83b1994897Sopenharmony_ci /** 84b1994897Sopenharmony_ci * Post barrier. Intergenerational barrier for GCs with explicit continuous young gen space. Unconditional. 85b1994897Sopenharmony_ci * Can be fully encoded by compiler 86b1994897Sopenharmony_ci * Pseudocode: 87b1994897Sopenharmony_ci * store obj.field <- new_val // STORE for which barrier generated 88b1994897Sopenharmony_ci * load AddressOf(MIN_ADDR) -> min_addr 89b1994897Sopenharmony_ci * load AddressOf(CARD_TABLE_ADDR) -> card_table_addr 90b1994897Sopenharmony_ci * card_index = (AddressOf(obj) - min_addr) >> CARD_BITS // shift right 91b1994897Sopenharmony_ci * card_addr = card_table_addr + card_index 92b1994897Sopenharmony_ci * store card_addr <- DIRTY_VAL 93b1994897Sopenharmony_ci * 94b1994897Sopenharmony_ci * Runtime should provide these parameters: 95b1994897Sopenharmony_ci * MIN_ADDR - minimal address used by runtime (it is required only to support 64-bit addresses) 96b1994897Sopenharmony_ci * CARD_TABLE_ADDR - address of the start of card table raw data array 97b1994897Sopenharmony_ci * CARD_BITS - how many bits covered by one card (probably it will be a literal) 98b1994897Sopenharmony_ci * DIRTY_VAL - some literal representing dirty card 99b1994897Sopenharmony_ci * 100b1994897Sopenharmony_ci * Note if store if to expensive on the architecture(for example in multithreading environment) - 101b1994897Sopenharmony_ci * consider to create conditional barrier, ie check that card is not dirty before store 102b1994897Sopenharmony_ci */ 103b1994897Sopenharmony_ci POST_INTERGENERATIONAL_BARRIER = 104b1994897Sopenharmony_ci EncodeBarrierType(3U, BarrierPosition::BARRIER_POSITION_POST, BarrierActionType::WRITE_BARRIER), 105b1994897Sopenharmony_ci /** 106b1994897Sopenharmony_ci * Inter-region barrier. For GCs without explicit continuous young gen space. 107b1994897Sopenharmony_ci * Pseudocode: 108b1994897Sopenharmony_ci * store obj.field <- new_val // STORE for which barrier generated 109b1994897Sopenharmony_ci * // Check if new_val is nullptr first - then we don't need a barrier 110b1994897Sopenharmony_ci * if (new_val == null) { 111b1994897Sopenharmony_ci * return 112b1994897Sopenharmony_ci * } 113b1994897Sopenharmony_ci * // Check if new_val and address of field is in different regions 114b1994897Sopenharmony_ci * // (each region contain 2^REGION_SIZE_BITS and aligned with 2^REGION_SIZE_BITS bytes) 115b1994897Sopenharmony_ci * if ((AddressOf(obj) XOR AddressOf(new_val)) >> REGION_SIZE_BITS) != 0) { 116b1994897Sopenharmony_ci * call UPDATE_CARD_FUNC(obj, new_val); 117b1994897Sopenharmony_ci * } 118b1994897Sopenharmony_ci * 119b1994897Sopenharmony_ci * Runtime should provide these parameters: 120b1994897Sopenharmony_ci * REGION_SIZE_BITS - log2 of the size of region 121b1994897Sopenharmony_ci * UPDATE_CARD_FUNC - function which updates card corresponding to the obj.field 122b1994897Sopenharmony_ci */ 123b1994897Sopenharmony_ci POST_INTERREGION_BARRIER = 124b1994897Sopenharmony_ci EncodeBarrierType(4U, BarrierPosition::BARRIER_POSITION_POST, BarrierActionType::WRITE_BARRIER), 125b1994897Sopenharmony_ci /* Note: cosider two-level card table for pre-barrier */ 126b1994897Sopenharmony_ci}; 127b1994897Sopenharmony_ci 128b1994897Sopenharmony_ciconstexpr bool IsPreBarrier(BarrierType barrier_type) 129b1994897Sopenharmony_ci{ 130b1994897Sopenharmony_ci return BitField<uint8_t, internal::BARRIER_POS_OFFSET, 1>::Get(barrier_type) == 131b1994897Sopenharmony_ci BarrierPosition::BARRIER_POSITION_PRE; 132b1994897Sopenharmony_ci} 133b1994897Sopenharmony_ci 134b1994897Sopenharmony_ciconstexpr bool IsPostBarrier(BarrierType barrier_type) 135b1994897Sopenharmony_ci{ 136b1994897Sopenharmony_ci return BitField<uint8_t, internal::BARRIER_POS_OFFSET, 1>::Get(barrier_type) == 137b1994897Sopenharmony_ci BarrierPosition::BARRIER_POSITION_POST; 138b1994897Sopenharmony_ci} 139b1994897Sopenharmony_ci 140b1994897Sopenharmony_ciconstexpr bool IsWriteBarrier(BarrierType barrier_type) 141b1994897Sopenharmony_ci{ 142b1994897Sopenharmony_ci return BitField<uint8_t, internal::BARRIER_WRB_FLAG_OFFSET, 1>::Get(barrier_type) == 143b1994897Sopenharmony_ci BarrierActionType::WRITE_BARRIER; 144b1994897Sopenharmony_ci} 145b1994897Sopenharmony_ci 146b1994897Sopenharmony_ciconstexpr bool IsReadBarrier(BarrierType barrier_type) 147b1994897Sopenharmony_ci{ 148b1994897Sopenharmony_ci return BitField<uint8_t, internal::BARRIER_WRB_FLAG_OFFSET, 1>::Get(barrier_type) == 149b1994897Sopenharmony_ci BarrierActionType::READ_BARRIER; 150b1994897Sopenharmony_ci} 151b1994897Sopenharmony_ci 152b1994897Sopenharmony_cistatic_assert(IsPreBarrier(BarrierType::PRE_SATB_BARRIER)); 153b1994897Sopenharmony_cistatic_assert(IsWriteBarrier(BarrierType::PRE_SATB_BARRIER)); 154b1994897Sopenharmony_cistatic_assert(IsPostBarrier(BarrierType::POST_INTERGENERATIONAL_BARRIER)); 155b1994897Sopenharmony_cistatic_assert(IsWriteBarrier(BarrierType::POST_INTERGENERATIONAL_BARRIER)); 156b1994897Sopenharmony_cistatic_assert(IsPostBarrier(BarrierType::POST_INTERREGION_BARRIER)); 157b1994897Sopenharmony_cistatic_assert(IsWriteBarrier(BarrierType::POST_INTERREGION_BARRIER)); 158b1994897Sopenharmony_ci 159b1994897Sopenharmony_ciconstexpr bool IsEmptyBarrier(BarrierType barrier_type) 160b1994897Sopenharmony_ci{ 161b1994897Sopenharmony_ci return (barrier_type == BarrierType::PRE_WRB_NONE) || (barrier_type == BarrierType::POST_WRB_NONE) || 162b1994897Sopenharmony_ci (barrier_type == BarrierType::PRE_RB_NONE) || (barrier_type == BarrierType::POST_RB_NONE); 163b1994897Sopenharmony_ci} 164b1994897Sopenharmony_ci 165b1994897Sopenharmony_ciusing objRefProcessFunc = void (*)(void *); 166b1994897Sopenharmony_ciusing objTwoRefProcessFunc = void (*)(const void *, const void *); 167b1994897Sopenharmony_ci 168b1994897Sopenharmony_cienum class BarrierOperandType { 169b1994897Sopenharmony_ci ADDRESS = 0, // just an address (void*) 170b1994897Sopenharmony_ci BOOL_ADDRESS, // contains address of bool value (bool*) 171b1994897Sopenharmony_ci UINT8_ADDRESS, // contains address of uint8_t value 172b1994897Sopenharmony_ci FUNC_WITH_OBJ_REF_ADDRESS, // contains address of function with this sig: void foo(void* ); 173b1994897Sopenharmony_ci UINT8_LITERAL, // contains uint8_t value 174b1994897Sopenharmony_ci FUNC_WITH_TWO_OBJ_REF_ADDRESSES, // contains address of function with this sig: void foo(void* , void* ); 175b1994897Sopenharmony_ci}; 176b1994897Sopenharmony_ci 177b1994897Sopenharmony_ciusing BarrierOperandValue = 178b1994897Sopenharmony_ci std::variant<void *, bool *, std::atomic<bool> *, uint8_t *, objRefProcessFunc, uint8_t, objTwoRefProcessFunc>; 179b1994897Sopenharmony_ci 180b1994897Sopenharmony_ciclass BarrierOperand { 181b1994897Sopenharmony_cipublic: 182b1994897Sopenharmony_ci // NOLINTNEXTLINE(modernize-pass-by-value) 183b1994897Sopenharmony_ci BarrierOperand(BarrierOperandType barrier_operand_type, BarrierOperandValue barrier_operand_value) 184b1994897Sopenharmony_ci : barrier_operand_type_(barrier_operand_type), barrier_operand_value_(barrier_operand_value) 185b1994897Sopenharmony_ci { 186b1994897Sopenharmony_ci } 187b1994897Sopenharmony_ci 188b1994897Sopenharmony_ci inline BarrierOperandType GetType() const 189b1994897Sopenharmony_ci { 190b1994897Sopenharmony_ci return barrier_operand_type_; 191b1994897Sopenharmony_ci } 192b1994897Sopenharmony_ci 193b1994897Sopenharmony_ci inline BarrierOperandValue GetValue() const 194b1994897Sopenharmony_ci { 195b1994897Sopenharmony_ci return barrier_operand_value_; 196b1994897Sopenharmony_ci } 197b1994897Sopenharmony_ci 198b1994897Sopenharmony_ci virtual ~BarrierOperand() = default; 199b1994897Sopenharmony_ci 200b1994897Sopenharmony_ci DEFAULT_COPY_SEMANTIC(BarrierOperand); 201b1994897Sopenharmony_ci DEFAULT_MOVE_SEMANTIC(BarrierOperand); 202b1994897Sopenharmony_ci 203b1994897Sopenharmony_ciprivate: 204b1994897Sopenharmony_ci BarrierOperandType barrier_operand_type_; 205b1994897Sopenharmony_ci BarrierOperandValue barrier_operand_value_; 206b1994897Sopenharmony_ci}; 207b1994897Sopenharmony_ci 208b1994897Sopenharmony_ci} // namespace panda::mem 209b1994897Sopenharmony_ci 210b1994897Sopenharmony_ci#endif // LIBPANDABASE_MEM_GC_BARRIER_H 211