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