• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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