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#include "ecmascript/mem/mem_map_allocator.h"
174514f5e3Sopenharmony_ci#include "ecmascript/platform/os.h"
184514f5e3Sopenharmony_ci
194514f5e3Sopenharmony_cinamespace panda::ecmascript {
204514f5e3Sopenharmony_ciMemMapAllocator *MemMapAllocator::GetInstance()
214514f5e3Sopenharmony_ci{
224514f5e3Sopenharmony_ci    static MemMapAllocator *vmAllocator_ = new MemMapAllocator();
234514f5e3Sopenharmony_ci    return vmAllocator_;
244514f5e3Sopenharmony_ci}
254514f5e3Sopenharmony_ci
264514f5e3Sopenharmony_civoid MemMapAllocator::InitializeRegularRegionMap([[maybe_unused]] size_t alignment)
274514f5e3Sopenharmony_ci{
284514f5e3Sopenharmony_ci#if defined(PANDA_TARGET_64) && !WIN_OR_MAC_OR_IOS_PLATFORM
294514f5e3Sopenharmony_ci    size_t initialRegularObjectCapacity = std::min(capacity_ / 2, INITIAL_REGULAR_OBJECT_CAPACITY);
304514f5e3Sopenharmony_ci    size_t i = 0;
314514f5e3Sopenharmony_ci    while (i < MEM_MAP_RETRY_NUM) {
324514f5e3Sopenharmony_ci        void *addr = reinterpret_cast<void *>(ToUintPtr(RandomGenerateBigAddr(REGULAR_OBJECT_MEM_MAP_BEGIN_ADDR)) +
334514f5e3Sopenharmony_ci            i * STEP_INCREASE_MEM_MAP_ADDR);
344514f5e3Sopenharmony_ci        MemMap memMap = PageMap(initialRegularObjectCapacity, PAGE_PROT_NONE, alignment, addr);
354514f5e3Sopenharmony_ci        if (ToUintPtr(memMap.GetMem()) >= ToUintPtr(addr)) {
364514f5e3Sopenharmony_ci            PageTag(memMap.GetMem(), memMap.GetSize(), PageTagType::MEMPOOL_CACHE);
374514f5e3Sopenharmony_ci            PageRelease(memMap.GetMem(), memMap.GetSize());
384514f5e3Sopenharmony_ci            memMapPool_.InsertMemMap(memMap);
394514f5e3Sopenharmony_ci            memMapPool_.SplitMemMapToCache(memMap);
404514f5e3Sopenharmony_ci            break;
414514f5e3Sopenharmony_ci        } else {
424514f5e3Sopenharmony_ci            PageUnmap(memMap);
434514f5e3Sopenharmony_ci            LOG_ECMA(ERROR) << "Regular object mem map big addr fail: " << errno;
444514f5e3Sopenharmony_ci        }
454514f5e3Sopenharmony_ci        i++;
464514f5e3Sopenharmony_ci    }
474514f5e3Sopenharmony_ci#endif
484514f5e3Sopenharmony_ci}
494514f5e3Sopenharmony_ci
504514f5e3Sopenharmony_civoid MemMapAllocator::InitializeHugeRegionMap(size_t alignment)
514514f5e3Sopenharmony_ci{
524514f5e3Sopenharmony_ci    size_t initialHugeObjectCapacity = std::min(capacity_ / 2, INITIAL_HUGE_OBJECT_CAPACITY);
534514f5e3Sopenharmony_ci#if defined(PANDA_TARGET_64) && !WIN_OR_MAC_OR_IOS_PLATFORM
544514f5e3Sopenharmony_ci    size_t i = 0;
554514f5e3Sopenharmony_ci    while (i <= MEM_MAP_RETRY_NUM) {
564514f5e3Sopenharmony_ci        void *addr = reinterpret_cast<void *>(ToUintPtr(RandomGenerateBigAddr(HUGE_OBJECT_MEM_MAP_BEGIN_ADDR)) +
574514f5e3Sopenharmony_ci            i * STEP_INCREASE_MEM_MAP_ADDR);
584514f5e3Sopenharmony_ci        MemMap memMap = PageMap(initialHugeObjectCapacity, PAGE_PROT_NONE, alignment, addr);
594514f5e3Sopenharmony_ci        if (ToUintPtr(memMap.GetMem()) >= ToUintPtr(addr) || i == MEM_MAP_RETRY_NUM) {
604514f5e3Sopenharmony_ci            PageTag(memMap.GetMem(), memMap.GetSize(), PageTagType::MEMPOOL_CACHE);
614514f5e3Sopenharmony_ci            PageRelease(memMap.GetMem(), memMap.GetSize());
624514f5e3Sopenharmony_ci            memMapFreeList_.Initialize(memMap, capacity_);
634514f5e3Sopenharmony_ci            break;
644514f5e3Sopenharmony_ci        } else {
654514f5e3Sopenharmony_ci            PageUnmap(memMap);
664514f5e3Sopenharmony_ci            LOG_ECMA(ERROR) << "Huge object mem map big addr fail: " << errno;
674514f5e3Sopenharmony_ci        }
684514f5e3Sopenharmony_ci        i++;
694514f5e3Sopenharmony_ci    }
704514f5e3Sopenharmony_ci#else
714514f5e3Sopenharmony_ci    MemMap hugeMemMap = PageMap(initialHugeObjectCapacity, PAGE_PROT_NONE, alignment);
724514f5e3Sopenharmony_ci    PageTag(hugeMemMap.GetMem(), hugeMemMap.GetSize(), PageTagType::MEMPOOL_CACHE);
734514f5e3Sopenharmony_ci    PageRelease(hugeMemMap.GetMem(), hugeMemMap.GetSize());
744514f5e3Sopenharmony_ci    memMapFreeList_.Initialize(hugeMemMap, capacity_);
754514f5e3Sopenharmony_ci#endif
764514f5e3Sopenharmony_ci}
774514f5e3Sopenharmony_ci
784514f5e3Sopenharmony_cistatic bool PageProtectMem(bool machineCodeSpace, void *mem, size_t size, [[maybe_unused]] bool isEnableJitFort)
794514f5e3Sopenharmony_ci{
804514f5e3Sopenharmony_ci    int prot = machineCodeSpace ? PAGE_PROT_EXEC_READWRITE : PAGE_PROT_READWRITE;
814514f5e3Sopenharmony_ci
824514f5e3Sopenharmony_ci    if (!machineCodeSpace) {
834514f5e3Sopenharmony_ci        return PageProtect(mem, size, prot);
844514f5e3Sopenharmony_ci    }
854514f5e3Sopenharmony_ci
864514f5e3Sopenharmony_ci    // MachineCode and HugeMachineCode space pages:
874514f5e3Sopenharmony_ci#if defined(PANDA_TARGET_ARM64) && defined(PANDA_TARGET_OHOS)
884514f5e3Sopenharmony_ci    if (isEnableJitFort) {
894514f5e3Sopenharmony_ci        // if JitFort enabled, Jit code will be in JitFort space, so only need READWRITE here
904514f5e3Sopenharmony_ci        return PageProtect(mem, size, PAGE_PROT_READWRITE);
914514f5e3Sopenharmony_ci    } else {
924514f5e3Sopenharmony_ci        // else Jit code will be in MachineCode space, need EXEC_READWRITE and MAP_EXECUTABLE (0x1000)
934514f5e3Sopenharmony_ci        void *addr = PageMapExecFortSpace(mem, size, PAGE_PROT_EXEC_READWRITE);
944514f5e3Sopenharmony_ci        if (addr != mem) {
954514f5e3Sopenharmony_ci            return false;
964514f5e3Sopenharmony_ci        }
974514f5e3Sopenharmony_ci        return true;
984514f5e3Sopenharmony_ci    }
994514f5e3Sopenharmony_ci#else
1004514f5e3Sopenharmony_ci    // not running phone kernel. Jit code will be MachineCode space
1014514f5e3Sopenharmony_ci    return PageProtect(mem, size, PAGE_PROT_EXEC_READWRITE);
1024514f5e3Sopenharmony_ci#endif
1034514f5e3Sopenharmony_ci}
1044514f5e3Sopenharmony_ci
1054514f5e3Sopenharmony_ciMemMap MemMapAllocator::Allocate(const uint32_t threadId, size_t size, size_t alignment,
1064514f5e3Sopenharmony_ci                                 const std::string &spaceName, bool regular, bool isMachineCode, bool isEnableJitFort)
1074514f5e3Sopenharmony_ci{
1084514f5e3Sopenharmony_ci    MemMap mem;
1094514f5e3Sopenharmony_ci    PageTagType type = isMachineCode ? PageTagType::MACHINE_CODE : PageTagType::HEAP;
1104514f5e3Sopenharmony_ci
1114514f5e3Sopenharmony_ci    if (regular) {
1124514f5e3Sopenharmony_ci        mem = memMapPool_.GetRegularMemFromCommitted(size);
1134514f5e3Sopenharmony_ci        if (mem.GetMem() != nullptr) {
1144514f5e3Sopenharmony_ci            bool res = PageProtectMem(isMachineCode, mem.GetMem(), mem.GetSize(), isEnableJitFort);
1154514f5e3Sopenharmony_ci            if (!res) {
1164514f5e3Sopenharmony_ci                return MemMap();
1174514f5e3Sopenharmony_ci            }
1184514f5e3Sopenharmony_ci            PageTag(mem.GetMem(), size, type, spaceName, threadId);
1194514f5e3Sopenharmony_ci            return mem;
1204514f5e3Sopenharmony_ci        }
1214514f5e3Sopenharmony_ci        if (UNLIKELY(memMapTotalSize_ + size > capacity_)) {
1224514f5e3Sopenharmony_ci            LOG_GC(ERROR) << "memory map overflow";
1234514f5e3Sopenharmony_ci            return MemMap();
1244514f5e3Sopenharmony_ci        }
1254514f5e3Sopenharmony_ci        mem = memMapPool_.GetMemFromCache(size);
1264514f5e3Sopenharmony_ci        if (mem.GetMem() != nullptr) {
1274514f5e3Sopenharmony_ci            memMapTotalSize_ += size;
1284514f5e3Sopenharmony_ci            bool res = PageProtectMem(isMachineCode, mem.GetMem(), mem.GetSize(), isEnableJitFort);
1294514f5e3Sopenharmony_ci            if (!res) {
1304514f5e3Sopenharmony_ci                return MemMap();
1314514f5e3Sopenharmony_ci            }
1324514f5e3Sopenharmony_ci            PageTag(mem.GetMem(), size, type, spaceName, threadId);
1334514f5e3Sopenharmony_ci            return mem;
1344514f5e3Sopenharmony_ci        }
1354514f5e3Sopenharmony_ci        mem = PageMap(REGULAR_REGION_MMAP_SIZE, PAGE_PROT_NONE, alignment);
1364514f5e3Sopenharmony_ci        memMapPool_.InsertMemMap(mem);
1374514f5e3Sopenharmony_ci        mem = memMapPool_.SplitMemFromCache(mem);
1384514f5e3Sopenharmony_ci    } else {
1394514f5e3Sopenharmony_ci        if (UNLIKELY(memMapTotalSize_ + size > capacity_)) {
1404514f5e3Sopenharmony_ci            LOG_GC(ERROR) << "memory map overflow";
1414514f5e3Sopenharmony_ci            return MemMap();
1424514f5e3Sopenharmony_ci        }
1434514f5e3Sopenharmony_ci        mem = memMapFreeList_.GetMemFromList(size);
1444514f5e3Sopenharmony_ci    }
1454514f5e3Sopenharmony_ci    if (mem.GetMem() != nullptr) {
1464514f5e3Sopenharmony_ci        bool res = PageProtectMem(isMachineCode, mem.GetMem(), mem.GetSize(), isEnableJitFort);
1474514f5e3Sopenharmony_ci        if (!res) {
1484514f5e3Sopenharmony_ci            return MemMap();
1494514f5e3Sopenharmony_ci        }
1504514f5e3Sopenharmony_ci        PageTag(mem.GetMem(), mem.GetSize(), type, spaceName, threadId);
1514514f5e3Sopenharmony_ci        memMapTotalSize_ += mem.GetSize();
1524514f5e3Sopenharmony_ci    }
1534514f5e3Sopenharmony_ci    return mem;
1544514f5e3Sopenharmony_ci}
1554514f5e3Sopenharmony_ci
1564514f5e3Sopenharmony_civoid MemMapAllocator::CacheOrFree(void *mem, size_t size, bool isRegular, size_t cachedSize)
1574514f5e3Sopenharmony_ci{
1584514f5e3Sopenharmony_ci    if (isRegular && !memMapPool_.IsRegularCommittedFull(cachedSize)) {
1594514f5e3Sopenharmony_ci        // Cache regions to accelerate allocation.
1604514f5e3Sopenharmony_ci        // Clear ThreadId tag and tag the mem with ARKTS HEAP.
1614514f5e3Sopenharmony_ci        PageClearTag(mem, size);
1624514f5e3Sopenharmony_ci        PageTag(mem, size, PageTagType::HEAP);
1634514f5e3Sopenharmony_ci        memMapPool_.AddMemToCommittedCache(mem, size);
1644514f5e3Sopenharmony_ci        return;
1654514f5e3Sopenharmony_ci    }
1664514f5e3Sopenharmony_ci    Free(mem, size, isRegular);
1674514f5e3Sopenharmony_ci    if (isRegular && memMapPool_.ShouldFreeMore(cachedSize) > 0) {
1684514f5e3Sopenharmony_ci        int freeNum = memMapPool_.ShouldFreeMore(cachedSize);
1694514f5e3Sopenharmony_ci        for (int i = 0; i < freeNum; i++) {
1704514f5e3Sopenharmony_ci            void *freeMem = memMapPool_.GetRegularMemFromCommitted(size).GetMem();
1714514f5e3Sopenharmony_ci            if (freeMem != nullptr) {
1724514f5e3Sopenharmony_ci                Free(freeMem, size, isRegular);
1734514f5e3Sopenharmony_ci            } else {
1744514f5e3Sopenharmony_ci                return;
1754514f5e3Sopenharmony_ci            }
1764514f5e3Sopenharmony_ci        }
1774514f5e3Sopenharmony_ci    }
1784514f5e3Sopenharmony_ci}
1794514f5e3Sopenharmony_ci
1804514f5e3Sopenharmony_civoid MemMapAllocator::Free(void *mem, size_t size, bool isRegular)
1814514f5e3Sopenharmony_ci{
1824514f5e3Sopenharmony_ci    memMapTotalSize_ -= size;
1834514f5e3Sopenharmony_ci    PageTag(mem, size, PageTagType::MEMPOOL_CACHE);
1844514f5e3Sopenharmony_ci    if (!PageProtect(mem, size, PAGE_PROT_NONE)) {
1854514f5e3Sopenharmony_ci        return;
1864514f5e3Sopenharmony_ci    }
1874514f5e3Sopenharmony_ci    PageRelease(mem, size);
1884514f5e3Sopenharmony_ci    if (isRegular) {
1894514f5e3Sopenharmony_ci        memMapPool_.AddMemToCache(mem, size);
1904514f5e3Sopenharmony_ci    } else {
1914514f5e3Sopenharmony_ci        memMapFreeList_.AddMemToList(MemMap(mem, size));
1924514f5e3Sopenharmony_ci    }
1934514f5e3Sopenharmony_ci}
1944514f5e3Sopenharmony_ci
1954514f5e3Sopenharmony_civoid MemMapAllocator::AdapterSuitablePoolCapacity()
1964514f5e3Sopenharmony_ci{
1974514f5e3Sopenharmony_ci    size_t physicalSize = PhysicalSize();
1984514f5e3Sopenharmony_ci    capacity_ = std::min<size_t>(physicalSize * DEFAULT_CAPACITY_RATE, MAX_MEM_POOL_CAPACITY);
1994514f5e3Sopenharmony_ci    LOG_GC(INFO) << "Ark Auto adapter memory pool capacity:" << capacity_;
2004514f5e3Sopenharmony_ci}
2014514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
202