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