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_MEM_MAP_ALLOCATOR_H
174514f5e3Sopenharmony_ci#define ECMASCRIPT_MEM_MEM_MAP_ALLOCATOR_H
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_ci#include <deque>
204514f5e3Sopenharmony_ci#include <map>
214514f5e3Sopenharmony_ci#include <random>
224514f5e3Sopenharmony_ci#include <set>
234514f5e3Sopenharmony_ci
244514f5e3Sopenharmony_ci#include "ecmascript/platform/map.h"
254514f5e3Sopenharmony_ci#include "ecmascript/mem/mem.h"
264514f5e3Sopenharmony_ci#include "ecmascript/mem/mem_common.h"
274514f5e3Sopenharmony_ci#include "ecmascript/log_wrapper.h"
284514f5e3Sopenharmony_ci
294514f5e3Sopenharmony_ci#include "ecmascript/platform/mutex.h"
304514f5e3Sopenharmony_ci
314514f5e3Sopenharmony_cinamespace panda::ecmascript {
324514f5e3Sopenharmony_ci// Regular region with length of DEFAULT_REGION_SIZE(256kb)
334514f5e3Sopenharmony_ciclass MemMapPool {
344514f5e3Sopenharmony_cipublic:
354514f5e3Sopenharmony_ci    MemMapPool() = default;
364514f5e3Sopenharmony_ci    ~MemMapPool() = default;
374514f5e3Sopenharmony_ci
384514f5e3Sopenharmony_ci    void Finalize()
394514f5e3Sopenharmony_ci    {
404514f5e3Sopenharmony_ci        LockHolder lock(lock_);
414514f5e3Sopenharmony_ci        for (auto &it : memMapVector_) {
424514f5e3Sopenharmony_ci            PageUnmap(it);
434514f5e3Sopenharmony_ci        }
444514f5e3Sopenharmony_ci        for (auto &it : regularMapCommitted_) {
454514f5e3Sopenharmony_ci            PageUnmap(it);
464514f5e3Sopenharmony_ci        }
474514f5e3Sopenharmony_ci        regularMapCommitted_.clear();
484514f5e3Sopenharmony_ci        memMapVector_.clear();
494514f5e3Sopenharmony_ci        memMapCache_.clear();
504514f5e3Sopenharmony_ci    }
514514f5e3Sopenharmony_ci
524514f5e3Sopenharmony_ci    NO_COPY_SEMANTIC(MemMapPool);
534514f5e3Sopenharmony_ci    NO_MOVE_SEMANTIC(MemMapPool);
544514f5e3Sopenharmony_ci
554514f5e3Sopenharmony_ci    MemMap GetMemFromCache([[maybe_unused]] size_t size)
564514f5e3Sopenharmony_ci    {
574514f5e3Sopenharmony_ci        ASSERT(size == REGULAR_MMAP_SIZE);
584514f5e3Sopenharmony_ci        LockHolder lock(lock_);
594514f5e3Sopenharmony_ci        if (!memMapCache_.empty()) {
604514f5e3Sopenharmony_ci            MemMap mem = memMapCache_.front();
614514f5e3Sopenharmony_ci            memMapCache_.pop_front();
624514f5e3Sopenharmony_ci            return mem;
634514f5e3Sopenharmony_ci        }
644514f5e3Sopenharmony_ci        return MemMap();
654514f5e3Sopenharmony_ci    }
664514f5e3Sopenharmony_ci
674514f5e3Sopenharmony_ci    MemMap GetRegularMemFromCommitted([[maybe_unused]] size_t size)
684514f5e3Sopenharmony_ci    {
694514f5e3Sopenharmony_ci        ASSERT(size == REGULAR_MMAP_SIZE);
704514f5e3Sopenharmony_ci        LockHolder lock(lock_);
714514f5e3Sopenharmony_ci        if (!regularMapCommitted_.empty()) {
724514f5e3Sopenharmony_ci            MemMap mem = regularMapCommitted_.back();
734514f5e3Sopenharmony_ci            regularMapCommitted_.pop_back();
744514f5e3Sopenharmony_ci            return mem;
754514f5e3Sopenharmony_ci        }
764514f5e3Sopenharmony_ci        return MemMap();
774514f5e3Sopenharmony_ci    }
784514f5e3Sopenharmony_ci
794514f5e3Sopenharmony_ci    bool IsRegularCommittedFull(size_t cachedSize)
804514f5e3Sopenharmony_ci    {
814514f5e3Sopenharmony_ci        LockHolder lock(lock_);
824514f5e3Sopenharmony_ci        size_t size = regularMapCommitted_.size();
834514f5e3Sopenharmony_ci        return size >= (cachedSize / REGULAR_MMAP_SIZE) ? true : false;
844514f5e3Sopenharmony_ci    }
854514f5e3Sopenharmony_ci
864514f5e3Sopenharmony_ci    int ShouldFreeMore(size_t cachedSize)
874514f5e3Sopenharmony_ci    {
884514f5e3Sopenharmony_ci        LockHolder lock(lock_);
894514f5e3Sopenharmony_ci        int result = static_cast<int>(regularMapCommitted_.size());
904514f5e3Sopenharmony_ci        return result - static_cast<int>(cachedSize / REGULAR_MMAP_SIZE);
914514f5e3Sopenharmony_ci    }
924514f5e3Sopenharmony_ci
934514f5e3Sopenharmony_ci    void AddMemToCommittedCache(void *mem, size_t size)
944514f5e3Sopenharmony_ci    {
954514f5e3Sopenharmony_ci        ASSERT(size == REGULAR_MMAP_SIZE);
964514f5e3Sopenharmony_ci        LockHolder lock(lock_);
974514f5e3Sopenharmony_ci        regularMapCommitted_.emplace_back(mem, size);
984514f5e3Sopenharmony_ci    }
994514f5e3Sopenharmony_ci
1004514f5e3Sopenharmony_ci    void AddMemToCache(void *mem, size_t size)
1014514f5e3Sopenharmony_ci    {
1024514f5e3Sopenharmony_ci        ASSERT(size == REGULAR_MMAP_SIZE);
1034514f5e3Sopenharmony_ci        LockHolder lock(lock_);
1044514f5e3Sopenharmony_ci        memMapCache_.emplace_back(mem, size);
1054514f5e3Sopenharmony_ci    }
1064514f5e3Sopenharmony_ci
1074514f5e3Sopenharmony_ci    MemMap SplitMemFromCache(MemMap memMap)
1084514f5e3Sopenharmony_ci    {
1094514f5e3Sopenharmony_ci        LockHolder lock(lock_);
1104514f5e3Sopenharmony_ci        auto remainderMem = reinterpret_cast<uintptr_t>(memMap.GetMem()) + REGULAR_MMAP_SIZE;
1114514f5e3Sopenharmony_ci        size_t remainderSize = AlignDown(memMap.GetSize() - REGULAR_MMAP_SIZE, REGULAR_MMAP_SIZE);
1124514f5e3Sopenharmony_ci        size_t count = remainderSize / REGULAR_MMAP_SIZE;
1134514f5e3Sopenharmony_ci        while (count-- > 0) {
1144514f5e3Sopenharmony_ci            memMapCache_.emplace_back(reinterpret_cast<void *>(remainderMem), REGULAR_MMAP_SIZE);
1154514f5e3Sopenharmony_ci            remainderMem = remainderMem + REGULAR_MMAP_SIZE;
1164514f5e3Sopenharmony_ci        }
1174514f5e3Sopenharmony_ci        return MemMap(memMap.GetMem(), REGULAR_MMAP_SIZE);
1184514f5e3Sopenharmony_ci    }
1194514f5e3Sopenharmony_ci
1204514f5e3Sopenharmony_ci    void SplitMemMapToCache(MemMap memMap)
1214514f5e3Sopenharmony_ci    {
1224514f5e3Sopenharmony_ci        auto memAddr = reinterpret_cast<uintptr_t>(memMap.GetMem());
1234514f5e3Sopenharmony_ci        size_t memTotalSize = AlignDown(memMap.GetSize(), REGULAR_MMAP_SIZE);
1244514f5e3Sopenharmony_ci        size_t count = memTotalSize / REGULAR_MMAP_SIZE;
1254514f5e3Sopenharmony_ci        while (count-- > 0) {
1264514f5e3Sopenharmony_ci            memMapCache_.emplace_back(reinterpret_cast<void *>(memAddr), REGULAR_MMAP_SIZE);
1274514f5e3Sopenharmony_ci            memAddr += REGULAR_MMAP_SIZE;
1284514f5e3Sopenharmony_ci        }
1294514f5e3Sopenharmony_ci    }
1304514f5e3Sopenharmony_ci
1314514f5e3Sopenharmony_ci    void InsertMemMap(MemMap memMap)
1324514f5e3Sopenharmony_ci    {
1334514f5e3Sopenharmony_ci        LockHolder lock(lock_);
1344514f5e3Sopenharmony_ci        memMapVector_.emplace_back(memMap);
1354514f5e3Sopenharmony_ci    }
1364514f5e3Sopenharmony_ci
1374514f5e3Sopenharmony_ciprivate:
1384514f5e3Sopenharmony_ci    static constexpr size_t REGULAR_MMAP_SIZE = 256_KB;
1394514f5e3Sopenharmony_ci    Mutex lock_;
1404514f5e3Sopenharmony_ci    std::deque<MemMap> memMapCache_;
1414514f5e3Sopenharmony_ci    std::vector<MemMap> regularMapCommitted_;
1424514f5e3Sopenharmony_ci    std::vector<MemMap> memMapVector_;
1434514f5e3Sopenharmony_ci};
1444514f5e3Sopenharmony_ci
1454514f5e3Sopenharmony_ci// Non regular region with length of DEFAULT_REGION_SIZE(256kb) multiple
1464514f5e3Sopenharmony_ciclass MemMapFreeList {
1474514f5e3Sopenharmony_cipublic:
1484514f5e3Sopenharmony_ci    MemMapFreeList() = default;
1494514f5e3Sopenharmony_ci    ~MemMapFreeList() = default;
1504514f5e3Sopenharmony_ci
1514514f5e3Sopenharmony_ci    void Initialize(MemMap memMap, size_t capacity)
1524514f5e3Sopenharmony_ci    {
1534514f5e3Sopenharmony_ci        memMaps_.emplace_back(memMap);
1544514f5e3Sopenharmony_ci        freeList_.emplace(memMap.GetSize(), memMap);
1554514f5e3Sopenharmony_ci        capacity_ = capacity;
1564514f5e3Sopenharmony_ci    }
1574514f5e3Sopenharmony_ci
1584514f5e3Sopenharmony_ci    void Finalize()
1594514f5e3Sopenharmony_ci    {
1604514f5e3Sopenharmony_ci        for (auto &memMap : memMaps_) {
1614514f5e3Sopenharmony_ci            PageUnmap(memMap);
1624514f5e3Sopenharmony_ci        }
1634514f5e3Sopenharmony_ci        memMaps_.clear();
1644514f5e3Sopenharmony_ci        freeList_.clear();
1654514f5e3Sopenharmony_ci    }
1664514f5e3Sopenharmony_ci
1674514f5e3Sopenharmony_ci    NO_COPY_SEMANTIC(MemMapFreeList);
1684514f5e3Sopenharmony_ci    NO_MOVE_SEMANTIC(MemMapFreeList);
1694514f5e3Sopenharmony_ci
1704514f5e3Sopenharmony_ci    void MergeList()
1714514f5e3Sopenharmony_ci    {
1724514f5e3Sopenharmony_ci        auto it = freeList_.begin();
1734514f5e3Sopenharmony_ci        while (it != freeList_.end()) {
1744514f5e3Sopenharmony_ci            bool isEqual = false;
1754514f5e3Sopenharmony_ci            void *startMem = (*it).second.GetMem();
1764514f5e3Sopenharmony_ci            size_t newSize = (*it).second.GetSize();
1774514f5e3Sopenharmony_ci            auto startIt = it++;
1784514f5e3Sopenharmony_ci            if (it == freeList_.end()) {
1794514f5e3Sopenharmony_ci                break;
1804514f5e3Sopenharmony_ci            }
1814514f5e3Sopenharmony_ci            auto next = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(startMem) + newSize);
1824514f5e3Sopenharmony_ci            while (it != freeList_.end() && next == (*it).second.GetMem()) {
1834514f5e3Sopenharmony_ci                newSize += (*it).second.GetSize();
1844514f5e3Sopenharmony_ci                it = freeList_.erase(it);
1854514f5e3Sopenharmony_ci                next = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(startMem) + newSize);
1864514f5e3Sopenharmony_ci                isEqual = true;
1874514f5e3Sopenharmony_ci            }
1884514f5e3Sopenharmony_ci            if (isEqual) {
1894514f5e3Sopenharmony_ci                freeList_.erase(startIt);
1904514f5e3Sopenharmony_ci                freeList_.emplace(newSize, MemMap(startMem, newSize));
1914514f5e3Sopenharmony_ci            }
1924514f5e3Sopenharmony_ci        }
1934514f5e3Sopenharmony_ci    }
1944514f5e3Sopenharmony_ci
1954514f5e3Sopenharmony_ci    MemMap GetMemFromList(size_t size)
1964514f5e3Sopenharmony_ci    {
1974514f5e3Sopenharmony_ci        if (freeListPoolSize_ + size > capacity_) {
1984514f5e3Sopenharmony_ci            LOG_GC(ERROR) << "Freelist pool oom: overflow(" << freeListPoolSize_ << ")";
1994514f5e3Sopenharmony_ci            return MemMap();
2004514f5e3Sopenharmony_ci        }
2014514f5e3Sopenharmony_ci        LockHolder lock(lock_);
2024514f5e3Sopenharmony_ci        auto iterate = freeList_.lower_bound(size);
2034514f5e3Sopenharmony_ci        if (iterate == freeList_.end()) {
2044514f5e3Sopenharmony_ci            MergeList();
2054514f5e3Sopenharmony_ci            iterate = freeList_.lower_bound(size);
2064514f5e3Sopenharmony_ci            // Unable to get memory from freeList, use PageMap
2074514f5e3Sopenharmony_ci            if (iterate == freeList_.end()) {
2084514f5e3Sopenharmony_ci                size_t incrementCapacity = std::max(size, INCREMENT_HUGE_OBJECT_CAPACITY);
2094514f5e3Sopenharmony_ci                MemMap smemMap = PageMap(incrementCapacity, PAGE_PROT_NONE, DEFAULT_REGION_SIZE);
2104514f5e3Sopenharmony_ci                LOG_GC(INFO) << "Huge object mem pool increase PageMap size: " << smemMap.GetSize();
2114514f5e3Sopenharmony_ci                memMaps_.emplace_back(smemMap);
2124514f5e3Sopenharmony_ci                freeList_.emplace(smemMap.GetSize(), smemMap);
2134514f5e3Sopenharmony_ci                iterate = freeList_.lower_bound(size);
2144514f5e3Sopenharmony_ci                ASSERT(iterate != freeList_.end());
2154514f5e3Sopenharmony_ci            }
2164514f5e3Sopenharmony_ci        }
2174514f5e3Sopenharmony_ci        MemMap memMap = iterate->second;
2184514f5e3Sopenharmony_ci        size_t remainderSize = memMap.GetSize() - size;
2194514f5e3Sopenharmony_ci        freeList_.erase(iterate);
2204514f5e3Sopenharmony_ci        if (remainderSize >= DEFAULT_REGION_SIZE) {
2214514f5e3Sopenharmony_ci            auto next = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(memMap.GetMem()) + size);
2224514f5e3Sopenharmony_ci            freeList_.emplace(remainderSize, MemMap(next, remainderSize));
2234514f5e3Sopenharmony_ci        }
2244514f5e3Sopenharmony_ci        freeListPoolSize_ += size;
2254514f5e3Sopenharmony_ci        return MemMap(memMap.GetMem(), size);
2264514f5e3Sopenharmony_ci    }
2274514f5e3Sopenharmony_ci
2284514f5e3Sopenharmony_ci    void AddMemToList(MemMap memMap)
2294514f5e3Sopenharmony_ci    {
2304514f5e3Sopenharmony_ci        LockHolder lock(lock_);
2314514f5e3Sopenharmony_ci        freeListPoolSize_ -= memMap.GetSize();
2324514f5e3Sopenharmony_ci        freeList_.emplace(memMap.GetSize(), memMap);
2334514f5e3Sopenharmony_ci    }
2344514f5e3Sopenharmony_ci
2354514f5e3Sopenharmony_ciprivate:
2364514f5e3Sopenharmony_ci    Mutex lock_;
2374514f5e3Sopenharmony_ci    std::vector<MemMap> memMaps_;
2384514f5e3Sopenharmony_ci    std::multimap<size_t, MemMap> freeList_;
2394514f5e3Sopenharmony_ci    std::atomic_size_t freeListPoolSize_ {0};
2404514f5e3Sopenharmony_ci    size_t capacity_ {0};
2414514f5e3Sopenharmony_ci};
2424514f5e3Sopenharmony_ci
2434514f5e3Sopenharmony_ciclass MemMapAllocator {
2444514f5e3Sopenharmony_cipublic:
2454514f5e3Sopenharmony_ci    MemMapAllocator() = default;
2464514f5e3Sopenharmony_ci    ~MemMapAllocator() = default;
2474514f5e3Sopenharmony_ci
2484514f5e3Sopenharmony_ci    NO_COPY_SEMANTIC(MemMapAllocator);
2494514f5e3Sopenharmony_ci    NO_MOVE_SEMANTIC(MemMapAllocator);
2504514f5e3Sopenharmony_ci
2514514f5e3Sopenharmony_ci    void Initialize(size_t alignment)
2524514f5e3Sopenharmony_ci    {
2534514f5e3Sopenharmony_ci        AdapterSuitablePoolCapacity();
2544514f5e3Sopenharmony_ci        memMapTotalSize_ = 0;
2554514f5e3Sopenharmony_ci        InitializeHugeRegionMap(alignment);
2564514f5e3Sopenharmony_ci        InitializeRegularRegionMap(alignment);
2574514f5e3Sopenharmony_ci    }
2584514f5e3Sopenharmony_ci
2594514f5e3Sopenharmony_ci    void Finalize()
2604514f5e3Sopenharmony_ci    {
2614514f5e3Sopenharmony_ci        memMapTotalSize_ = 0;
2624514f5e3Sopenharmony_ci        capacity_ = 0;
2634514f5e3Sopenharmony_ci        memMapFreeList_.Finalize();
2644514f5e3Sopenharmony_ci        memMapPool_.Finalize();
2654514f5e3Sopenharmony_ci    }
2664514f5e3Sopenharmony_ci
2674514f5e3Sopenharmony_ci    size_t GetCapacity()
2684514f5e3Sopenharmony_ci    {
2694514f5e3Sopenharmony_ci        return capacity_;
2704514f5e3Sopenharmony_ci    }
2714514f5e3Sopenharmony_ci
2724514f5e3Sopenharmony_ci    static MemMapAllocator *GetInstance();
2734514f5e3Sopenharmony_ci
2744514f5e3Sopenharmony_ci    MemMap Allocate(const uint32_t threadId, size_t size, size_t alignment,
2754514f5e3Sopenharmony_ci                    const std::string &spaceName, bool regular, bool isMachineCode,
2764514f5e3Sopenharmony_ci                    bool isEnableJitFort);
2774514f5e3Sopenharmony_ci
2784514f5e3Sopenharmony_ci    void CacheOrFree(void *mem, size_t size, bool isRegular, size_t cachedSize);
2794514f5e3Sopenharmony_ci
2804514f5e3Sopenharmony_ciprivate:
2814514f5e3Sopenharmony_ci    void InitializeRegularRegionMap(size_t alignment);
2824514f5e3Sopenharmony_ci    void InitializeHugeRegionMap(size_t alignment);
2834514f5e3Sopenharmony_ci    // Random generate big mem map addr to avoid js heap is written by others
2844514f5e3Sopenharmony_ci    void *RandomGenerateBigAddr(uint64_t addr)
2854514f5e3Sopenharmony_ci    {
2864514f5e3Sopenharmony_ci        // Use the current time as the seed
2874514f5e3Sopenharmony_ci        unsigned seed = static_cast<unsigned>(std::chrono::system_clock::now().time_since_epoch().count());
2884514f5e3Sopenharmony_ci        std::mt19937_64 generator(seed);
2894514f5e3Sopenharmony_ci
2904514f5e3Sopenharmony_ci        // Generate a random number between 0 and RANDOM_NUM_MAX
2914514f5e3Sopenharmony_ci        std::uniform_int_distribution<uint64_t> distribution(0, RANDOM_NUM_MAX);
2924514f5e3Sopenharmony_ci        uint64_t randomNum = distribution(generator);
2934514f5e3Sopenharmony_ci
2944514f5e3Sopenharmony_ci        // Big addr random change in 0x2000000000 ~ 0x2FF0000000
2954514f5e3Sopenharmony_ci        return reinterpret_cast<void *>(addr + (randomNum << RANDOM_SHIFT_BIT));
2964514f5e3Sopenharmony_ci    }
2974514f5e3Sopenharmony_ci
2984514f5e3Sopenharmony_ci    static constexpr size_t REGULAR_REGION_MMAP_SIZE = 4_MB;
2994514f5e3Sopenharmony_ci    static constexpr uint64_t HUGE_OBJECT_MEM_MAP_BEGIN_ADDR = 0x1000000000;
3004514f5e3Sopenharmony_ci    static constexpr uint64_t REGULAR_OBJECT_MEM_MAP_BEGIN_ADDR = 0x2000000000;
3014514f5e3Sopenharmony_ci    static constexpr uint64_t STEP_INCREASE_MEM_MAP_ADDR = 0x1000000000;
3024514f5e3Sopenharmony_ci    static constexpr size_t RANDOM_NUM_MAX = 0xFF;
3034514f5e3Sopenharmony_ci    static constexpr size_t RANDOM_SHIFT_BIT = 28;
3044514f5e3Sopenharmony_ci    static constexpr size_t MEM_MAP_RETRY_NUM = 10;
3054514f5e3Sopenharmony_ci
3064514f5e3Sopenharmony_ci    void AdapterSuitablePoolCapacity();
3074514f5e3Sopenharmony_ci    void Free(void *mem, size_t size, bool isRegular);
3084514f5e3Sopenharmony_ci    MemMapPool memMapPool_;
3094514f5e3Sopenharmony_ci    MemMapFreeList memMapFreeList_;
3104514f5e3Sopenharmony_ci    std::atomic_size_t memMapTotalSize_ {0};
3114514f5e3Sopenharmony_ci    size_t capacity_ {0};
3124514f5e3Sopenharmony_ci};
3134514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
3144514f5e3Sopenharmony_ci#endif  // ECMASCRIPT_MEM_MEM_MAP_ALLOCATOR_H
315