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