• 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 
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