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_MEMDESC_H 17 #define ECMASCRIPT_MEM_JIT_FORT_MEMDESC_H 18 19 #include <deque> 20 #include "ecmascript/js_tagged_value.h" 21 #include "ecmascript/base/asan_interface.h" 22 #include "ecmascript/platform/mutex.h" 23 24 namespace panda::ecmascript { 25 26 // Before Jit Fort, FreeList allocator uses FreeObject to link 27 // together free memory blocks in heap regions where each 28 // free memory block is a FreeObject with size of the block and 29 // a pointer to the next free block in the heap region. Its usage 30 // requires a mutable heap region and does not work with Jit Fort space 31 // which is immutbale execept for access by CodeSigner. 32 // 33 // When JIT Fort is enabled, JIT generated instructions are installed 34 // in memory allocated from JitFort space, and the corresponding mutable 35 // Code Cache object constains a pointer to the allocated blk. 36 // The information on free and used Jit Fort space is stored outside of 37 // JitFort using MemDesc which holds a pointer to a mem block in Jit Fort 38 // space, size of the block, and a pointer to the next MemDesc. It is 39 // used to maintain list of free mem blks in Jit Fort as well as list 40 // of live (in use) mem blocks. 41 // 42 // To reuse FreeList allocator code for JitFort, related classes 43 // (allocator/FreeObjectList/FreeObjectSet, etc) had to be changed into 44 // template classes to support both FreeObject and MemDesc targets, 45 // and MemDesc has to support same methods as FreeObject, and use the 46 // same null pointer value forlink pointer that FreeObject uses, i.e. 47 // NULL_POINTER with a value of 0x5 instead of 0. 48 // 49 #define INVALID_OBJPTR ((uintptr_t) JSTaggedValue::NULL_POINTER) 50 51 class MemDesc { 52 public: 53 MemDesc() = default; 54 ~MemDesc() = default; 55 Cast(uintptr_t object)56 static MemDesc *Cast(uintptr_t object) 57 { 58 return reinterpret_cast<MemDesc *>(object); 59 } 60 GetBegin()61 inline uintptr_t GetBegin() const 62 { 63 return mem_; 64 } 65 GetEnd()66 inline uintptr_t GetEnd() const 67 { 68 return mem_ + size_; 69 } 70 SetMem(uintptr_t mem)71 inline void SetMem(uintptr_t mem) 72 { 73 mem_ = mem; 74 } 75 SetSize(size_t size)76 inline void SetSize(size_t size) 77 { 78 size_ = size; 79 } 80 SetNext(MemDesc * desc)81 inline void SetNext(MemDesc *desc) 82 { 83 next_ = desc; 84 } 85 GetNext()86 inline MemDesc *GetNext() 87 { 88 return next_; 89 } 90 Available()91 inline uint32_t Available() const 92 { 93 return size_; 94 } 95 IsFreeObject()96 inline bool IsFreeObject() const 97 { 98 return true; // for compatibility with FreeObject 99 } 100 SetAvailable(uint32_t size)101 inline void SetAvailable(uint32_t size) 102 { 103 size_ = size; 104 } 105 AsanPoisonFreeObject()106 inline void AsanPoisonFreeObject() const 107 { 108 ASAN_POISON_MEMORY_REGION(mem_, size_); 109 } 110 AsanUnPoisonFreeObject()111 inline void AsanUnPoisonFreeObject() const 112 { 113 ASAN_UNPOISON_MEMORY_REGION(mem_, size_); 114 } 115 SetInstalled(bool installed)116 inline void SetInstalled(bool installed) 117 { 118 installed_.store(installed, std::memory_order_release); 119 } 120 IsInstalled()121 inline bool IsInstalled() 122 { 123 return installed_.load(std::memory_order_acquire); 124 } 125 126 private: 127 uintptr_t mem_ {0}; 128 size_t size_ {0}; 129 std::atomic<bool> installed_ {false}; 130 MemDesc *next_ {MemDesc::Cast(INVALID_OBJPTR)}; 131 }; 132 133 class MemDescPool { 134 public: 135 MemDescPool(uintptr_t fortBegin, size_t fortSize); 136 ~MemDescPool(); 137 IsEmpty(MemDesc * list)138 static inline bool IsEmpty(MemDesc* list) 139 { 140 return (list == nullptr || list == MemDesc::Cast(INVALID_OBJPTR)); 141 } 142 GetDescFromPool()143 inline MemDesc *GetDescFromPool() 144 { 145 LockHolder lock(lock_); 146 return GetDesc(); 147 } 148 ReturnDescToPool(MemDesc * desc)149 inline void ReturnDescToPool(MemDesc *desc) 150 { 151 LockHolder lock(lock_); 152 Add(desc); 153 returned_++; 154 } 155 JitFortBegin()156 inline uintptr_t JitFortBegin() 157 { 158 return fortBegin_; 159 } 160 JitFortSize()161 inline size_t JitFortSize() 162 { 163 return fortSize_; 164 } 165 166 private: 167 MemDesc *GetDesc(); 168 void Add(MemDesc *); 169 void Expand(); 170 171 static constexpr size_t MEMDESCS_PER_BLOCK = 100; 172 MemDesc *freeList_ {nullptr}; 173 std::deque<void *> memDescBlocks_; 174 size_t allocated_ {0}; 175 size_t returned_ {0}; 176 size_t highwater_ {0}; 177 Mutex lock_; 178 179 uintptr_t fortBegin_; 180 size_t fortSize_; 181 }; 182 183 } // namespace panda::ecmascript 184 185 #endif // ECMASCRIPT_MEM_JIT_FORT_MEMDESC_H 186