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/heap_region_allocator.h"
17
18 #include "ecmascript/ecma_vm.h"
19 #include "ecmascript/js_thread.h"
20 #include "ecmascript/mem/heap.h"
21 #include "ecmascript/mem/mark_stack.h"
22 #include "ecmascript/mem/mem_map_allocator.h"
23 #include "ecmascript/mem/region.h"
24 #include "ecmascript/mem/space-inl.h"
25 #include "ecmascript/platform/map.h"
26
27 namespace panda::ecmascript {
28 constexpr size_t PANDA_POOL_ALIGNMENT_IN_BYTES = 256_KB;
29
AllocateAlignedRegion(Space * space,size_t capacity,JSThread * thread)30 Region *HeapRegionAllocator::AllocateAlignedRegion(Space *space, size_t capacity, JSThread* thread)
31 {
32 if (capacity == 0) {
33 LOG_ECMA_MEM(FATAL) << "capacity must have a size bigger than 0";
34 UNREACHABLE();
35 }
36 RegionSpaceFlag flags = space->GetRegionFlag();
37 bool isRegular = (flags != RegionSpaceFlag::IN_HUGE_OBJECT_SPACE &&
38 flags != RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE);
39 bool isMachineCode = (flags == RegionSpaceFlag::IN_MACHINE_CODE_SPACE ||
40 flags == RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE);
41 auto pool = MemMapAllocator::GetInstance()->Allocate(thread->GetThreadId(), capacity, DEFAULT_REGION_SIZE,
42 ToSpaceTypeName(space->GetSpaceType()),
43 isRegular, isMachineCode);
44 void *mapMem = pool.GetMem();
45 if (mapMem == nullptr) {
46 const_cast<Heap *>(thread->GetEcmaVM()->GetHeap())->ThrowOutOfMemoryErrorForDefault(DEFAULT_REGION_SIZE,
47 "HeapRegionAllocator::AllocateAlignedRegion", false);
48 LOG_ECMA_MEM(FATAL) << "pool is empty " << annoMemoryUsage_.load(std::memory_order_relaxed);
49 UNREACHABLE();
50 }
51 #if ECMASCRIPT_ENABLE_ZAP_MEM
52 if (memset_s(mapMem, capacity, 0, capacity) != EOK) {
53 LOG_FULL(FATAL) << "memset_s failed";
54 UNREACHABLE();
55 }
56 #endif
57 IncreaseAnnoMemoryUsage(capacity);
58
59 uintptr_t mem = ToUintPtr(mapMem);
60 // Check that the address is 256K byte aligned
61 LOG_ECMA_IF(AlignUp(mem, PANDA_POOL_ALIGNMENT_IN_BYTES) != mem, FATAL) << "region not align by 256KB";
62
63 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
64 uintptr_t begin = AlignUp(mem + sizeof(Region), static_cast<size_t>(MemAlignment::MEM_ALIGN_REGION));
65 uintptr_t end = mem + capacity;
66
67 Region *region = new (ToVoidPtr(mem)) Region(thread, mem, begin, end, flags);
68 std::atomic_thread_fence(std::memory_order_seq_cst);
69 return region;
70 }
71
FreeRegion(Region * region,size_t cachedSize)72 void HeapRegionAllocator::FreeRegion(Region *region, size_t cachedSize)
73 {
74 auto size = region->GetCapacity();
75 bool isRegular = !region->InHugeObjectSpace() && !region->InHugeMachineCodeSpace();
76 auto allocateBase = region->GetAllocateBase();
77
78 DecreaseAnnoMemoryUsage(size);
79 region->Invalidate();
80 region->ClearMembers();
81 #if ECMASCRIPT_ENABLE_ZAP_MEM
82 if (memset_s(ToVoidPtr(allocateBase), size, INVALID_VALUE, size) != EOK) {
83 LOG_FULL(FATAL) << "memset_s failed";
84 UNREACHABLE();
85 }
86 #endif
87 MemMapAllocator::GetInstance()->CacheOrFree(ToVoidPtr(allocateBase),
88 size, isRegular, cachedSize);
89 }
90 } // namespace panda::ecmascript
91