14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#ifndef ECMASCRIPT_MEM_GC_BITSET__H 174514f5e3Sopenharmony_ci#define ECMASCRIPT_MEM_GC_BITSET__H 184514f5e3Sopenharmony_ci 194514f5e3Sopenharmony_ci#include <atomic> 204514f5e3Sopenharmony_ci#include <bitset> 214514f5e3Sopenharmony_ci 224514f5e3Sopenharmony_ci#include "ecmascript/base/math_helper.h" 234514f5e3Sopenharmony_ci#include "ecmascript/mem/mem.h" 244514f5e3Sopenharmony_ci 254514f5e3Sopenharmony_ci// |----word(32 bit)----|----word(32 bit)----|----...----|----word(32 bit)----|----word(32 bit)----| 264514f5e3Sopenharmony_ci// |---------------------------------------GCBitset(4 kb)------------------------------------------| 274514f5e3Sopenharmony_ci 284514f5e3Sopenharmony_cinamespace panda::ecmascript { 294514f5e3Sopenharmony_cienum class AccessType { ATOMIC, NON_ATOMIC }; 304514f5e3Sopenharmony_ci 314514f5e3Sopenharmony_ciclass GCBitset { 324514f5e3Sopenharmony_cipublic: 334514f5e3Sopenharmony_ci using GCBitsetWord = uint32_t; 344514f5e3Sopenharmony_ci using GCBitsetTwoWords = uint64_t; 354514f5e3Sopenharmony_ci static constexpr uint32_t BYTE_PER_WORD = sizeof(GCBitsetWord); 364514f5e3Sopenharmony_ci static constexpr uint32_t BYTE_PER_WORD_LOG2 = base::MathHelper::GetIntLog2(BYTE_PER_WORD); 374514f5e3Sopenharmony_ci static constexpr uint32_t BIT_PER_BYTE = 8; 384514f5e3Sopenharmony_ci static constexpr uint32_t BIT_PER_BYTE_LOG2 = base::MathHelper::GetIntLog2(BIT_PER_BYTE); 394514f5e3Sopenharmony_ci static constexpr uint32_t BIT_PER_WORD = BYTE_PER_WORD * BIT_PER_BYTE; 404514f5e3Sopenharmony_ci static constexpr uint32_t BIT_PER_WORD_LOG2 = base::MathHelper::GetIntLog2(BIT_PER_WORD); 414514f5e3Sopenharmony_ci static constexpr uint32_t BIT_PER_WORD_MASK = BIT_PER_WORD - 1; 424514f5e3Sopenharmony_ci 434514f5e3Sopenharmony_ci GCBitset() = default; 444514f5e3Sopenharmony_ci ~GCBitset() = default; 454514f5e3Sopenharmony_ci 464514f5e3Sopenharmony_ci NO_COPY_SEMANTIC(GCBitset); 474514f5e3Sopenharmony_ci NO_MOVE_SEMANTIC(GCBitset); 484514f5e3Sopenharmony_ci 494514f5e3Sopenharmony_ci static size_t SizeOfGCBitset(size_t heapSize) 504514f5e3Sopenharmony_ci { 514514f5e3Sopenharmony_ci size_t bitSize = AlignUp(heapSize, TAGGED_TYPE_SIZE) >> TAGGED_TYPE_SIZE_LOG; 524514f5e3Sopenharmony_ci return AlignUp(AlignUp(bitSize, BIT_PER_BYTE) >> BIT_PER_BYTE_LOG2, BYTE_PER_WORD); 534514f5e3Sopenharmony_ci } 544514f5e3Sopenharmony_ci 554514f5e3Sopenharmony_ci GCBitsetWord *Words() 564514f5e3Sopenharmony_ci { 574514f5e3Sopenharmony_ci return reinterpret_cast<GCBitsetWord *>(this); 584514f5e3Sopenharmony_ci } 594514f5e3Sopenharmony_ci 604514f5e3Sopenharmony_ci GCBitsetTwoWords *TwoWords() 614514f5e3Sopenharmony_ci { 624514f5e3Sopenharmony_ci return reinterpret_cast<GCBitsetTwoWords *>(this); 634514f5e3Sopenharmony_ci } 644514f5e3Sopenharmony_ci 654514f5e3Sopenharmony_ci const GCBitsetWord *Words() const 664514f5e3Sopenharmony_ci { 674514f5e3Sopenharmony_ci return reinterpret_cast<const GCBitsetWord *>(this); 684514f5e3Sopenharmony_ci } 694514f5e3Sopenharmony_ci 704514f5e3Sopenharmony_ci void SetGCWords(uint32_t index) // Only used for snapshot to record region index 714514f5e3Sopenharmony_ci { 724514f5e3Sopenharmony_ci *reinterpret_cast<GCBitsetWord *>(this) = index; 734514f5e3Sopenharmony_ci } 744514f5e3Sopenharmony_ci 754514f5e3Sopenharmony_ci void Clear(size_t bitSize) 764514f5e3Sopenharmony_ci { 774514f5e3Sopenharmony_ci GCBitsetWord *words = Words(); 784514f5e3Sopenharmony_ci uint32_t wordCount = static_cast<uint32_t>(WordCount(bitSize)); 794514f5e3Sopenharmony_ci for (uint32_t i = 0; i < wordCount; i++) { 804514f5e3Sopenharmony_ci words[i] = 0; 814514f5e3Sopenharmony_ci } 824514f5e3Sopenharmony_ci } 834514f5e3Sopenharmony_ci 844514f5e3Sopenharmony_ci void SetAllBits(size_t bitSize) 854514f5e3Sopenharmony_ci { 864514f5e3Sopenharmony_ci GCBitsetWord *words = Words(); 874514f5e3Sopenharmony_ci uint32_t wordCount = static_cast<uint32_t>(WordCount(bitSize)); 884514f5e3Sopenharmony_ci GCBitsetWord mask = 0; 894514f5e3Sopenharmony_ci for (uint32_t i = 0; i < wordCount; i++) { 904514f5e3Sopenharmony_ci words[i] = ~mask; 914514f5e3Sopenharmony_ci } 924514f5e3Sopenharmony_ci } 934514f5e3Sopenharmony_ci 944514f5e3Sopenharmony_ci template <AccessType mode = AccessType::NON_ATOMIC> 954514f5e3Sopenharmony_ci bool SetBit(uintptr_t offset); 964514f5e3Sopenharmony_ci 974514f5e3Sopenharmony_ci bool SetBitRange(uintptr_t offset, uint32_t mask); 984514f5e3Sopenharmony_ci 994514f5e3Sopenharmony_ci void ClearBit(uintptr_t offset) 1004514f5e3Sopenharmony_ci { 1014514f5e3Sopenharmony_ci Words()[Index(offset)] &= ~Mask(IndexInWord(offset)); 1024514f5e3Sopenharmony_ci } 1034514f5e3Sopenharmony_ci 1044514f5e3Sopenharmony_ci template <AccessType mode = AccessType::NON_ATOMIC> 1054514f5e3Sopenharmony_ci void ClearBitRange(uintptr_t offsetBegin, uintptr_t offsetEnd) 1064514f5e3Sopenharmony_ci { 1074514f5e3Sopenharmony_ci GCBitsetWord *words = Words(); 1084514f5e3Sopenharmony_ci uint32_t startIndex = Index(offsetBegin); 1094514f5e3Sopenharmony_ci uint32_t startIndexMask = Mask(IndexInWord(offsetBegin)); 1104514f5e3Sopenharmony_ci ASSERT(offsetEnd > 0); 1114514f5e3Sopenharmony_ci uint32_t endIndex = Index(offsetEnd - 1); 1124514f5e3Sopenharmony_ci uint32_t endIndexMask = Mask(IndexInWord(offsetEnd - 1)); 1134514f5e3Sopenharmony_ci ASSERT(startIndex <= endIndex); 1144514f5e3Sopenharmony_ci if (startIndex != endIndex) { 1154514f5e3Sopenharmony_ci ClearWord<mode>(startIndex, ~(startIndexMask - 1)); 1164514f5e3Sopenharmony_ci ClearWord<mode>(endIndex, endIndexMask | (endIndexMask - 1)); 1174514f5e3Sopenharmony_ci while (++startIndex < endIndex) { 1184514f5e3Sopenharmony_ci words[startIndex] = 0; 1194514f5e3Sopenharmony_ci } 1204514f5e3Sopenharmony_ci } else { 1214514f5e3Sopenharmony_ci ClearWord<mode>(endIndex, endIndexMask | (endIndexMask - startIndexMask)); 1224514f5e3Sopenharmony_ci } 1234514f5e3Sopenharmony_ci } 1244514f5e3Sopenharmony_ci 1254514f5e3Sopenharmony_ci bool TestBit(uintptr_t offset) const 1264514f5e3Sopenharmony_ci { 1274514f5e3Sopenharmony_ci return Words()[Index(offset)] & Mask(IndexInWord(offset)); 1284514f5e3Sopenharmony_ci } 1294514f5e3Sopenharmony_ci 1304514f5e3Sopenharmony_ci template <typename Visitor, AccessType mode = AccessType::NON_ATOMIC> 1314514f5e3Sopenharmony_ci void IterateMarkedBits(uintptr_t begin, size_t bitSize, Visitor visitor) 1324514f5e3Sopenharmony_ci { 1334514f5e3Sopenharmony_ci auto words = Words(); 1344514f5e3Sopenharmony_ci uint32_t wordCount = WordCount(bitSize); 1354514f5e3Sopenharmony_ci uint32_t index = BIT_PER_WORD; 1364514f5e3Sopenharmony_ci for (uint32_t i = 0; i < wordCount; i++) { 1374514f5e3Sopenharmony_ci uint32_t word = words[i]; 1384514f5e3Sopenharmony_ci while (word != 0) { 1394514f5e3Sopenharmony_ci index = static_cast<uint32_t>(__builtin_ctz(word)); 1404514f5e3Sopenharmony_ci ASSERT(index < BIT_PER_WORD); 1414514f5e3Sopenharmony_ci if (!visitor(reinterpret_cast<void *>(begin + (index << TAGGED_TYPE_SIZE_LOG)))) { 1424514f5e3Sopenharmony_ci ClearWord<mode>(i, Mask(index)); 1434514f5e3Sopenharmony_ci } 1444514f5e3Sopenharmony_ci word &= ~(1u << index); 1454514f5e3Sopenharmony_ci } 1464514f5e3Sopenharmony_ci begin += TAGGED_TYPE_SIZE * BIT_PER_WORD; 1474514f5e3Sopenharmony_ci } 1484514f5e3Sopenharmony_ci } 1494514f5e3Sopenharmony_ci 1504514f5e3Sopenharmony_ci template <typename Visitor> 1514514f5e3Sopenharmony_ci void IterateMarkedBitsConst(uintptr_t begin, size_t bitSize, Visitor visitor) const 1524514f5e3Sopenharmony_ci { 1534514f5e3Sopenharmony_ci auto words = Words(); 1544514f5e3Sopenharmony_ci uint32_t wordCount = WordCount(bitSize); 1554514f5e3Sopenharmony_ci uint32_t index = BIT_PER_WORD; 1564514f5e3Sopenharmony_ci for (uint32_t i = 0; i < wordCount; i++) { 1574514f5e3Sopenharmony_ci uint32_t word = words[i]; 1584514f5e3Sopenharmony_ci while (word != 0) { 1594514f5e3Sopenharmony_ci index = static_cast<uint32_t>(__builtin_ctz(word)); 1604514f5e3Sopenharmony_ci ASSERT(index < BIT_PER_WORD); 1614514f5e3Sopenharmony_ci visitor(reinterpret_cast<void *>(begin + (index << TAGGED_TYPE_SIZE_LOG))); 1624514f5e3Sopenharmony_ci word &= ~(1u << index); 1634514f5e3Sopenharmony_ci } 1644514f5e3Sopenharmony_ci begin += TAGGED_TYPE_SIZE * BIT_PER_WORD; 1654514f5e3Sopenharmony_ci } 1664514f5e3Sopenharmony_ci } 1674514f5e3Sopenharmony_ci 1684514f5e3Sopenharmony_ci void Merge(GCBitset *bitset, size_t bitSize) 1694514f5e3Sopenharmony_ci { 1704514f5e3Sopenharmony_ci ASSERT(bitSize % sizeof(GCBitsetTwoWords) == 0); 1714514f5e3Sopenharmony_ci auto words = TwoWords(); 1724514f5e3Sopenharmony_ci uint32_t wordCount = TwoWordsCount(bitSize); 1734514f5e3Sopenharmony_ci for (uint32_t i = 0; i < wordCount; i++) { 1744514f5e3Sopenharmony_ci words[i] |= bitset->TwoWords()[i]; 1754514f5e3Sopenharmony_ci } 1764514f5e3Sopenharmony_ci } 1774514f5e3Sopenharmony_ci 1784514f5e3Sopenharmony_ciprivate: 1794514f5e3Sopenharmony_ci GCBitsetWord Mask(size_t index) const 1804514f5e3Sopenharmony_ci { 1814514f5e3Sopenharmony_ci return 1 << index; 1824514f5e3Sopenharmony_ci } 1834514f5e3Sopenharmony_ci 1844514f5e3Sopenharmony_ci size_t IndexInWord(uintptr_t offset) const 1854514f5e3Sopenharmony_ci { 1864514f5e3Sopenharmony_ci return offset & BIT_PER_WORD_MASK; 1874514f5e3Sopenharmony_ci } 1884514f5e3Sopenharmony_ci 1894514f5e3Sopenharmony_ci size_t Index(uintptr_t offset) const 1904514f5e3Sopenharmony_ci { 1914514f5e3Sopenharmony_ci return offset >> BIT_PER_WORD_LOG2; 1924514f5e3Sopenharmony_ci } 1934514f5e3Sopenharmony_ci 1944514f5e3Sopenharmony_ci size_t WordCount(size_t size) const 1954514f5e3Sopenharmony_ci { 1964514f5e3Sopenharmony_ci return size >> BYTE_PER_WORD_LOG2; 1974514f5e3Sopenharmony_ci } 1984514f5e3Sopenharmony_ci 1994514f5e3Sopenharmony_ci size_t TwoWordsCount(size_t size) const 2004514f5e3Sopenharmony_ci { 2014514f5e3Sopenharmony_ci return size >> (BYTE_PER_WORD_LOG2 + 1); 2024514f5e3Sopenharmony_ci } 2034514f5e3Sopenharmony_ci 2044514f5e3Sopenharmony_ci template <AccessType mode = AccessType::NON_ATOMIC> 2054514f5e3Sopenharmony_ci bool ClearWord(uint32_t index, uint32_t mask); 2064514f5e3Sopenharmony_ci 2074514f5e3Sopenharmony_ci template <> 2084514f5e3Sopenharmony_ci bool ClearWord<AccessType::NON_ATOMIC>(uint32_t index, uint32_t mask) 2094514f5e3Sopenharmony_ci { 2104514f5e3Sopenharmony_ci if ((Words()[index] & mask) == 0) { 2114514f5e3Sopenharmony_ci return false; 2124514f5e3Sopenharmony_ci } 2134514f5e3Sopenharmony_ci Words()[index] &= ~mask; 2144514f5e3Sopenharmony_ci return true; 2154514f5e3Sopenharmony_ci } 2164514f5e3Sopenharmony_ci 2174514f5e3Sopenharmony_ci template <> 2184514f5e3Sopenharmony_ci bool ClearWord<AccessType::ATOMIC>(uint32_t index, uint32_t mask) 2194514f5e3Sopenharmony_ci { 2204514f5e3Sopenharmony_ci volatile auto word = reinterpret_cast<volatile std::atomic<GCBitsetWord> *>(&Words()[index]); 2214514f5e3Sopenharmony_ci auto oldValue = word->load(std::memory_order_relaxed); 2224514f5e3Sopenharmony_ci GCBitsetWord oldValueBeforeCAS; 2234514f5e3Sopenharmony_ci do { 2244514f5e3Sopenharmony_ci if ((oldValue & mask) == 0) { 2254514f5e3Sopenharmony_ci return false; 2264514f5e3Sopenharmony_ci } 2274514f5e3Sopenharmony_ci oldValueBeforeCAS = oldValue; 2284514f5e3Sopenharmony_ci std::atomic_compare_exchange_strong_explicit(word, &oldValue, oldValue & (~mask), 2294514f5e3Sopenharmony_ci std::memory_order_release, std::memory_order_relaxed); 2304514f5e3Sopenharmony_ci } while (oldValue != oldValueBeforeCAS); 2314514f5e3Sopenharmony_ci return true; 2324514f5e3Sopenharmony_ci } 2334514f5e3Sopenharmony_ci}; 2344514f5e3Sopenharmony_ci 2354514f5e3Sopenharmony_ciinline bool GCBitset::SetBitRange(uintptr_t offset, uint32_t mask) 2364514f5e3Sopenharmony_ci{ 2374514f5e3Sopenharmony_ci size_t index = Index(offset); 2384514f5e3Sopenharmony_ci Words()[index] |= mask; 2394514f5e3Sopenharmony_ci return true; 2404514f5e3Sopenharmony_ci} 2414514f5e3Sopenharmony_ci 2424514f5e3Sopenharmony_citemplate <> 2434514f5e3Sopenharmony_ciinline bool GCBitset::SetBit<AccessType::NON_ATOMIC>(uintptr_t offset) 2444514f5e3Sopenharmony_ci{ 2454514f5e3Sopenharmony_ci size_t index = Index(offset); 2464514f5e3Sopenharmony_ci GCBitsetWord mask = Mask(IndexInWord(offset)); 2474514f5e3Sopenharmony_ci if (Words()[index] & mask) { 2484514f5e3Sopenharmony_ci return false; 2494514f5e3Sopenharmony_ci } 2504514f5e3Sopenharmony_ci Words()[index] |= mask; 2514514f5e3Sopenharmony_ci return true; 2524514f5e3Sopenharmony_ci} 2534514f5e3Sopenharmony_ci 2544514f5e3Sopenharmony_citemplate <> 2554514f5e3Sopenharmony_ciinline bool GCBitset::SetBit<AccessType::ATOMIC>(uintptr_t offset) 2564514f5e3Sopenharmony_ci{ 2574514f5e3Sopenharmony_ci volatile auto word = reinterpret_cast<volatile std::atomic<GCBitsetWord> *>(&Words()[Index(offset)]); 2584514f5e3Sopenharmony_ci auto mask = Mask(IndexInWord(offset)); 2594514f5e3Sopenharmony_ci auto oldValue = word->load(std::memory_order_relaxed); 2604514f5e3Sopenharmony_ci GCBitsetWord oldValueBeforeCAS; 2614514f5e3Sopenharmony_ci do { 2624514f5e3Sopenharmony_ci if (oldValue & mask) { 2634514f5e3Sopenharmony_ci return false; 2644514f5e3Sopenharmony_ci } 2654514f5e3Sopenharmony_ci oldValueBeforeCAS = oldValue; 2664514f5e3Sopenharmony_ci std::atomic_compare_exchange_strong_explicit(word, &oldValue, oldValue | mask, 2674514f5e3Sopenharmony_ci std::memory_order_release, std::memory_order_relaxed); 2684514f5e3Sopenharmony_ci } while (oldValue != oldValueBeforeCAS); 2694514f5e3Sopenharmony_ci return true; 2704514f5e3Sopenharmony_ci} 2714514f5e3Sopenharmony_ci 2724514f5e3Sopenharmony_citemplate <size_t BitSetNum, typename Enable = std::enable_if_t<(BitSetNum >= 1), int>> 2734514f5e3Sopenharmony_ciclass GCBitSetUpdater { 2744514f5e3Sopenharmony_cipublic: 2754514f5e3Sopenharmony_ci GCBitSetUpdater() = delete; 2764514f5e3Sopenharmony_ci 2774514f5e3Sopenharmony_ci explicit GCBitSetUpdater(uintptr_t updateAddress) 2784514f5e3Sopenharmony_ci : updateAddress_(updateAddress), 2794514f5e3Sopenharmony_ci cursor_((updateAddress >> TAGGED_TYPE_SIZE_LOG) & GCBitset::BIT_PER_WORD_MASK) 2804514f5e3Sopenharmony_ci { 2814514f5e3Sopenharmony_ci } 2824514f5e3Sopenharmony_ci 2834514f5e3Sopenharmony_ci NO_COPY_SEMANTIC(GCBitSetUpdater); 2844514f5e3Sopenharmony_ci 2854514f5e3Sopenharmony_ci ARK_INLINE void Update(size_t setIdx) 2864514f5e3Sopenharmony_ci { 2874514f5e3Sopenharmony_ci ASSERT(setIdx < BitSetNum); 2884514f5e3Sopenharmony_ci bitsets_[setIdx].set(cursor_); 2894514f5e3Sopenharmony_ci } 2904514f5e3Sopenharmony_ci 2914514f5e3Sopenharmony_ci ARK_INLINE bool Next() 2924514f5e3Sopenharmony_ci { 2934514f5e3Sopenharmony_ci cursor_++; 2944514f5e3Sopenharmony_ci ASSERT(cursor_ <= GCBitset::BIT_PER_WORD); 2954514f5e3Sopenharmony_ci return cursor_ == GCBitset::BIT_PER_WORD; 2964514f5e3Sopenharmony_ci } 2974514f5e3Sopenharmony_ci 2984514f5e3Sopenharmony_ci ARK_INLINE std::array<std::bitset<GCBitset::BIT_PER_WORD>, BitSetNum> GetAndResetAll(uintptr_t& updateAddress) 2994514f5e3Sopenharmony_ci { 3004514f5e3Sopenharmony_ci std::array<std::bitset<GCBitset::BIT_PER_WORD>, BitSetNum> retBitsets; 3014514f5e3Sopenharmony_ci std::swap(retBitsets, bitsets_); 3024514f5e3Sopenharmony_ci updateAddress = updateAddress_; 3034514f5e3Sopenharmony_ci 3044514f5e3Sopenharmony_ci cursor_ = 0; 3054514f5e3Sopenharmony_ci constexpr size_t ConsumeRange = GCBitset::BIT_PER_WORD * GCBitset::BIT_PER_BYTE; 3064514f5e3Sopenharmony_ci updateAddress_ = AlignDown(updateAddress_ + ConsumeRange, ConsumeRange); 3074514f5e3Sopenharmony_ci return retBitsets; 3084514f5e3Sopenharmony_ci } 3094514f5e3Sopenharmony_ci 3104514f5e3Sopenharmony_ciprivate: 3114514f5e3Sopenharmony_ci uintptr_t updateAddress_ = 0; 3124514f5e3Sopenharmony_ci std::array<std::bitset<GCBitset::BIT_PER_WORD>, BitSetNum> bitsets_; 3134514f5e3Sopenharmony_ci size_t cursor_ = 0; 3144514f5e3Sopenharmony_ci}; 3154514f5e3Sopenharmony_ci} // namespace panda::ecmascript 3164514f5e3Sopenharmony_ci#endif // ECMASCRIPT_MEM_GC_BITSET__H 317