1/* 2 * Copyright (c) 2024 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#ifndef ECMASCRIPT_MEM_JIT_FORT_H 17#define ECMASCRIPT_MEM_JIT_FORT_H 18 19#include <array> 20 21#include "ecmascript/mem/mem_common.h" 22#include "ecmascript/mem/region.h" 23#include "ecmascript/mem/machine_code.h" 24 25namespace panda::ecmascript { 26 27class JitFortRegion; 28class JitFortMemDescPool; 29template <typename T> 30class FreeListAllocator; 31 32class JitFort { 33public: 34 JitFort(); 35 ~JitFort(); 36 NO_COPY_SEMANTIC(JitFort); 37 NO_MOVE_SEMANTIC(JitFort); 38 39 void InitRegions(); 40 bool AddRegion(); 41 uintptr_t Allocate(MachineCodeDesc *desc); 42 43 inline JitFortRegion *GetRegionList() 44 { 45 return regionList_.GetFirst(); 46 } 47 48 inline uintptr_t JitFortBegin() 49 { 50 return jitFortBegin_; 51 } 52 53 inline size_t JitFortSize() 54 { 55 return jitFortSize_; 56 } 57 58 bool InRange(uintptr_t address) const; 59 void CollectFreeRanges(JitFortRegion *region); 60 void UpdateFreeSpace(); 61 62 JitFortRegion *ObjectAddressToRange(uintptr_t objAddress); 63 static void InitJitFortResource(); 64 void PrepareSweeping(); 65 void AsyncSweep(); 66 void Sweep(); 67 void MarkJitFortMemAlive(MachineCode *obj); 68 void MarkJitFortMemAwaitInstall(uintptr_t addr, size_t size); 69 void MarkJitFortMemInstalled(MachineCode *obj); 70 void FreeRegion(JitFortRegion *region); 71 uint32_t AddrToFortRegionIdx(uint64_t addr); 72 size_t FortAllocSize(size_t instrSize); 73 PUBLIC_API static bool IsResourceAvailable(); 74 75private: 76 static bool isResourceAvailable_; 77 FreeListAllocator<MemDesc> *allocator_ {nullptr}; 78 79 // Fort memory space 80 static constexpr int MAP_JITFORT = 0x1000; 81 static constexpr size_t JIT_FORT_REG_SPACE_MAX = 4_MB; 82 static constexpr size_t JIT_FORT_HUGE_SPACE_MAX = 2_MB; 83 static constexpr size_t JIT_FORT_MEM_DESC_MAX = 40_KB; 84 MemMap jitFortMem_; 85 uintptr_t jitFortBegin_ {0}; 86 size_t jitFortSize_ {0}; 87 88 // Fort regions 89 static constexpr uint32_t FORT_BUF_ALIGN = 32; 90 static constexpr uint32_t FORT_BUF_ALIGN_LOG2 = base::MathHelper::GetIntLog2(FORT_BUF_ALIGN); 91 static constexpr size_t FORT_BUF_ADDR_MASK = FORT_BUF_ALIGN - 1; 92 static constexpr size_t MAX_JIT_FORT_REGIONS = JIT_FORT_REG_SPACE_MAX/DEFAULT_REGION_SIZE; 93 std::array<JitFortRegion *, MAX_JIT_FORT_REGIONS>regions_; 94 size_t nextFreeRegionIdx_ {0}; 95 EcmaList<JitFortRegion> regionList_ {}; // regions in use by Jit Fort allocator 96 97 MemDescPool *memDescPool_ {nullptr}; 98 99 bool freeListUpdated_ {false}; // use atomic if not mutext protected 100 Mutex mutex_; 101 Mutex liveJitCodeBlksLock_; 102 std::atomic<bool> isSweeping_ {false}; 103 friend class HugeMachineCodeSpace; 104}; 105 106class JitFortGCBitset : public GCBitset { 107public: 108 JitFortGCBitset() = default; 109 ~JitFortGCBitset() = default; 110 111 NO_COPY_SEMANTIC(JitFortGCBitset); 112 NO_MOVE_SEMANTIC(JitFortGCBitset); 113 114 template <typename Visitor> 115 void IterateMarkedBitsConst(uintptr_t regionAddr, size_t bitsetSize, Visitor visitor); 116 void MarkStartAddr(bool awaitInstall, uintptr_t startAddr, uint32_t index, uint32_t &word); 117 void MarkEndAddr(bool awaitInstall, uintptr_t endAddr, uint32_t index, uint32_t &word); 118 119 size_t WordCount(size_t size) const 120 { 121 return size >> BYTE_PER_WORD_LOG2; 122 } 123 124 inline void ClearMark(uintptr_t addr) 125 { 126 ClearBit((addr & DEFAULT_REGION_MASK) >> TAGGED_TYPE_SIZE_LOG); 127 } 128 129 inline bool Test(uintptr_t addr) 130 { 131 return TestBit((addr & DEFAULT_REGION_MASK) >> TAGGED_TYPE_SIZE_LOG); 132 } 133}; 134 135class JitFortRegion : public Region { 136public: 137 JitFortRegion(NativeAreaAllocator *allocator, uintptr_t allocateBase, uintptr_t end, 138 RegionSpaceFlag spaceType, MemDescPool *pool) : Region(allocator, allocateBase, end, spaceType), 139 memDescPool_(pool) 140 { 141 markGCBitset_ = new(reinterpret_cast<void *>(gcBitSet_)) JitFortGCBitset(); 142 markGCBitset_->Clear(bitsetSize_); 143 InitializeFreeObjectSets(); 144 } 145 146 void InitializeFreeObjectSets() 147 { 148 fortFreeObjectSets_ = Span<FreeObjectSet<MemDesc> *>(new FreeObjectSet<MemDesc> 149 *[FreeObjectList<MemDesc>::NumberOfSets()](), FreeObjectList<MemDesc>::NumberOfSets()); 150 } 151 152 void DestroyFreeObjectSets() 153 { 154 for (auto set : fortFreeObjectSets_) { 155 delete set; 156 } 157 delete[] fortFreeObjectSets_.data(); 158 } 159 160 FreeObjectSet<MemDesc> *GetFreeObjectSet(SetType type) 161 { 162 // Thread safe 163 if (fortFreeObjectSets_[type] == nullptr) { 164 fortFreeObjectSets_[type] = new FreeObjectSet<MemDesc>(type, memDescPool_); 165 } 166 return fortFreeObjectSets_[type]; 167 } 168 169 inline void LinkNext(JitFortRegion *next) 170 { 171 next_ = next; 172 } 173 174 inline JitFortRegion *GetNext() const 175 { 176 return next_; 177 } 178 179 inline void LinkPrev(JitFortRegion *prev) 180 { 181 prev_ = prev; 182 } 183 184 inline JitFortRegion *GetPrev() const 185 { 186 return prev_; 187 } 188 189 inline JitFortGCBitset *GetGCBitset() 190 { 191 return markGCBitset_; 192 } 193 194 inline size_t GetGCBitsetSize() 195 { 196 return bitsetSize_; 197 } 198 199 inline bool AtomicMark(void *address) 200 { 201 auto addrPtr = reinterpret_cast<uintptr_t>(address); 202 ASSERT(InRange(addrPtr)); 203 return markGCBitset_->SetBit<AccessType::ATOMIC>( 204 (addrPtr & DEFAULT_REGION_MASK) >> TAGGED_TYPE_SIZE_LOG); 205 } 206 207private: 208 Span<FreeObjectSet<MemDesc> *> fortFreeObjectSets_; 209 JitFortRegion *next_ {nullptr}; 210 JitFortRegion *prev_ {nullptr}; 211 MemDescPool *memDescPool_ {nullptr}; 212 213 static constexpr int FORT_REGION_BITSET_SIZE = 4096; 214 size_t bitsetSize_ {FORT_REGION_BITSET_SIZE}; 215 alignas(uint64_t) uint8_t gcBitSet_[FORT_REGION_BITSET_SIZE]; 216 alignas(uint64_t) JitFortGCBitset *markGCBitset_ {nullptr}; 217}; 218 219} // namespace panda::ecmascript 220#endif // ECMASCRIPT_MEM_SPARSE_SPACE_H 221