1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "ecmascript/mem/mem_map_allocator.h"
17 #include "ecmascript/platform/map.h"
18 #include "ecmascript/platform/os.h"
19
20 namespace panda::ecmascript {
GetInstance()21 MemMapAllocator *MemMapAllocator::GetInstance()
22 {
23 static MemMapAllocator *vmAllocator_ = new MemMapAllocator();
24 return vmAllocator_;
25 }
26
Allocate(const uint32_t threadId,size_t size,size_t alignment,const std::string & spaceName,bool regular,bool isMachineCode)27 MemMap MemMapAllocator::Allocate(const uint32_t threadId, size_t size, size_t alignment,
28 const std::string &spaceName, bool regular, bool isMachineCode)
29 {
30 if (UNLIKELY(memMapTotalSize_ + size > capacity_)) {
31 LOG_GC(ERROR) << "memory map overflow";
32 return MemMap();
33 }
34
35 MemMap mem;
36 if (regular) {
37 mem = memMapPool_.GetRegularMemFromCommitted(size);
38 if (mem.GetMem() != nullptr) {
39 int prot = isMachineCode ? PAGE_PROT_EXEC_READWRITE : PAGE_PROT_READWRITE;
40 PageTagType type = isMachineCode ? PageTagType::MACHINE_CODE : PageTagType::HEAP;
41 PageProtect(mem.GetMem(), mem.GetSize(), prot);
42 PageTag(mem.GetMem(), size, type, spaceName, threadId);
43 return mem;
44 }
45 mem = memMapPool_.GetMemFromCache(size);
46 if (mem.GetMem() != nullptr) {
47 memMapTotalSize_ += size;
48 int prot = isMachineCode ? PAGE_PROT_EXEC_READWRITE : PAGE_PROT_READWRITE;
49 PageTagType type = isMachineCode ? PageTagType::MACHINE_CODE : PageTagType::HEAP;
50 PageProtect(mem.GetMem(), mem.GetSize(), prot);
51 PageTag(mem.GetMem(), size, type, spaceName, threadId);
52 return mem;
53 }
54 mem = PageMap(REGULAR_REGION_MMAP_SIZE, PAGE_PROT_NONE, alignment);
55 memMapPool_.InsertMemMap(mem);
56 mem = memMapPool_.SplitMemFromCache(mem);
57 } else {
58 mem = memMapFreeList_.GetMemFromList(size);
59 }
60 if (mem.GetMem() != nullptr) {
61 int prot = isMachineCode ? PAGE_PROT_EXEC_READWRITE : PAGE_PROT_READWRITE;
62 PageTagType type = isMachineCode ? PageTagType::MACHINE_CODE : PageTagType::HEAP;
63 PageProtect(mem.GetMem(), mem.GetSize(), prot);
64 PageTag(mem.GetMem(), mem.GetSize(), type, spaceName, threadId);
65 memMapTotalSize_ += mem.GetSize();
66 }
67 return mem;
68 }
69
CacheOrFree(void * mem,size_t size,bool isRegular,size_t cachedSize)70 void MemMapAllocator::CacheOrFree(void *mem, size_t size, bool isRegular, size_t cachedSize)
71 {
72 if (isRegular && !memMapPool_.IsRegularCommittedFull(cachedSize)) {
73 // Cache regions to accelerate allocation.
74 // Clear ThreadId tag and tag the mem with ARKTS HEAP.
75 PageClearTag(mem, size);
76 PageTag(mem, size, PageTagType::HEAP);
77 memMapPool_.AddMemToCommittedCache(mem, size);
78 return;
79 }
80 Free(mem, size, isRegular);
81 if (isRegular && memMapPool_.ShouldFreeMore(cachedSize) > 0) {
82 int freeNum = memMapPool_.ShouldFreeMore(cachedSize);
83 for (int i = 0; i < freeNum; i++) {
84 void *freeMem = memMapPool_.GetRegularMemFromCommitted(size).GetMem();
85 if (freeMem != nullptr) {
86 Free(freeMem, size, isRegular);
87 } else {
88 return;
89 }
90 }
91 }
92 }
93
Free(void * mem,size_t size,bool isRegular)94 void MemMapAllocator::Free(void *mem, size_t size, bool isRegular)
95 {
96 memMapTotalSize_ -= size;
97 PageTag(mem, size, PageTagType::MEMPOOL_CACHE);
98 PageProtect(mem, size, PAGE_PROT_NONE);
99 PageRelease(mem, size);
100 if (isRegular) {
101 memMapPool_.AddMemToCache(mem, size);
102 } else {
103 memMapFreeList_.AddMemToList(MemMap(mem, size));
104 }
105 }
106
AdapterSuitablePoolCapacity()107 void MemMapAllocator::AdapterSuitablePoolCapacity()
108 {
109 size_t physicalSize = PhysicalSize();
110 capacity_ = std::max<size_t>(physicalSize / PHY_SIZE_MULTIPLE, MIN_MEM_POOL_CAPACITY);
111 if (capacity_ > LARGE_POOL_SIZE) {
112 capacity_ = std::max<size_t>(capacity_, STANDARD_POOL_SIZE);
113 } else if (capacity_ >= MEDIUM_POOL_SIZE) {
114 capacity_ = std::min<size_t>(capacity_, STANDARD_POOL_SIZE);
115 } else if (capacity_ >= LOW_POOL_SIZE) {
116 capacity_ = std::max<size_t>(capacity_, 128_MB);
117 }
118 LOG_GC(INFO) << "Ark Auto adapter memory pool capacity:" << capacity_;
119 }
120 } // namespace panda::ecmascript
121