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