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