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, FreeObject usage is replaced by MemDesc 34 // which serves same purpose as FreeObjects, but is stored outside of 35 // JitFort memory space. 36 // 37 // To reuse FreeList allocator code for JitFort, related classes 38 // (allocator/FreeObjectList/FreeObjectSet, etc) had to be changed into 39 // template classes to support both FreeObject and MemDesc targets, 40 // and MemDesc has to support same methods as FreeObject, and use the 41 // same null pointer value forlink pointer that FreeObject uses, i.e. 42 // NULL_POINTER with a value of 0x5 instead of 0. 43 // 44 #define INVALID_OBJPTR ((uintptr_t) JSTaggedValue::NULL_POINTER) 45 46 class MemDesc { 47 public: 48 MemDesc() = default; 49 ~MemDesc() = default; 50 Cast(uintptr_t object)51 static MemDesc *Cast(uintptr_t object) 52 { 53 return reinterpret_cast<MemDesc *>(object); 54 } 55 GetBegin() const56 inline uintptr_t GetBegin() const 57 { 58 return mem_; 59 } 60 GetEnd() const61 inline uintptr_t GetEnd() const 62 { 63 return mem_ + size_; 64 } 65 SetMem(uintptr_t mem)66 inline void SetMem(uintptr_t mem) 67 { 68 mem_ = mem; 69 } 70 SetSize(size_t size)71 inline void SetSize(size_t size) 72 { 73 size_ = size; 74 } 75 SetNext(MemDesc *desc)76 inline void SetNext(MemDesc *desc) 77 { 78 next_ = desc; 79 } 80 GetNext()81 inline MemDesc *GetNext() 82 { 83 return next_; 84 } 85 Available() const86 inline uint32_t Available() const 87 { 88 return size_; 89 } 90 IsFreeObject() const91 inline bool IsFreeObject() const 92 { 93 return true; // for compatibility with FreeObject 94 } 95 SetAvailable(uint32_t size)96 inline void SetAvailable(uint32_t size) 97 { 98 size_ = size; 99 } 100 AsanPoisonFreeObject() const101 inline void AsanPoisonFreeObject() const 102 { 103 ASAN_POISON_MEMORY_REGION((const volatile void *)mem_, size_); 104 } 105 AsanUnPoisonFreeObject() const106 inline void AsanUnPoisonFreeObject() const 107 { 108 ASAN_UNPOISON_MEMORY_REGION((const volatile void *)mem_, size_); 109 } 110 SetInstalled(bool installed)111 inline void SetInstalled(bool installed) 112 { 113 installed_.store(installed, std::memory_order_release); 114 } 115 IsInstalled()116 inline bool IsInstalled() 117 { 118 return installed_.load(std::memory_order_acquire); 119 } 120 121 private: 122 uintptr_t mem_ {0}; 123 size_t size_ {0}; 124 std::atomic<bool> installed_ {false}; 125 MemDesc *next_ {MemDesc::Cast(INVALID_OBJPTR)}; 126 }; 127 128 class MemDescPool { 129 public: 130 MemDescPool(uintptr_t fortBegin, size_t fortSize); 131 ~MemDescPool(); 132 IsEmpty(MemDesc* list)133 static inline bool IsEmpty(MemDesc* list) 134 { 135 return (list == nullptr || list == MemDesc::Cast(INVALID_OBJPTR)); 136 } 137 GetDescFromPool()138 inline MemDesc *GetDescFromPool() 139 { 140 LockHolder lock(lock_); 141 return GetDesc(); 142 } 143 ReturnDescToPool(MemDesc *desc)144 inline void ReturnDescToPool(MemDesc *desc) 145 { 146 LockHolder lock(lock_); 147 Add(desc); 148 returned_++; 149 } 150 JitFortBegin()151 inline uintptr_t JitFortBegin() 152 { 153 return fortBegin_; 154 } 155 JitFortSize()156 inline size_t JitFortSize() 157 { 158 return fortSize_; 159 } 160 161 private: 162 MemDesc *GetDesc(); 163 void Add(MemDesc *); 164 void Expand(); 165 166 static constexpr size_t MEMDESCS_PER_BLOCK = 100; 167 MemDesc *freeList_ {nullptr}; 168 std::deque<void *> memDescBlocks_; 169 size_t allocated_ {0}; 170 size_t returned_ {0}; 171 size_t highwater_ {0}; 172 Mutex lock_; 173 174 uintptr_t fortBegin_; 175 size_t fortSize_; 176 }; 177 178 } // namespace panda::ecmascript 179 180 #endif // ECMASCRIPT_MEM_JIT_FORT_MEMDESC_H 181