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_H
17 #define ECMASCRIPT_MEM_JIT_FORT_H
18 
19 #include <array>
20 
21 #include "ecmascript/mem/mem_common.h"
22 #include "ecmascript/mem/region.h"
23 #include "ecmascript/mem/machine_code.h"
24 
25 namespace panda::ecmascript {
26 
27 class JitFortRegion;
28 class JitFortMemDescPool;
29 template <typename T>
30 class FreeListAllocator;
31 
32 class JitFort {
33 public:
34     JitFort();
35     ~JitFort();
36     NO_COPY_SEMANTIC(JitFort);
37     NO_MOVE_SEMANTIC(JitFort);
38 
39     void InitRegions();
40     bool AddRegion();
41     uintptr_t Allocate(MachineCodeDesc *desc);
42 
GetRegionList()43     inline JitFortRegion *GetRegionList()
44     {
45         return regionList_.GetFirst();
46     }
47 
JitFortBegin()48     inline uintptr_t JitFortBegin()
49     {
50         return jitFortBegin_;
51     }
52 
JitFortSize()53     inline size_t JitFortSize()
54     {
55         return jitFortSize_;
56     }
57 
58     bool InRange(uintptr_t address) const;
59     void CollectFreeRanges(JitFortRegion  *region);
60     void UpdateFreeSpace();
61 
62     JitFortRegion *ObjectAddressToRange(uintptr_t objAddress);
63     static void InitJitFortResource();
64     void PrepareSweeping();
65     void AsyncSweep();
66     void Sweep();
67     void MarkJitFortMemAlive(MachineCode *obj);
68     void MarkJitFortMemAwaitInstall(uintptr_t addr, size_t size);
69     void MarkJitFortMemInstalled(MachineCode *obj);
70     void FreeRegion(JitFortRegion *region);
71     uint32_t AddrToFortRegionIdx(uint64_t addr);
72     size_t FortAllocSize(size_t instrSize);
73     PUBLIC_API static bool IsResourceAvailable();
74 
75 private:
76     static bool isResourceAvailable_;
77     FreeListAllocator<MemDesc> *allocator_ {nullptr};
78 
79     // Fort memory space
80     static constexpr int MAP_JITFORT = 0x1000;
81     static constexpr size_t JIT_FORT_REG_SPACE_MAX = 4_MB;
82     static constexpr size_t JIT_FORT_HUGE_SPACE_MAX = 2_MB;
83     static constexpr size_t JIT_FORT_MEM_DESC_MAX = 40_KB;
84     MemMap jitFortMem_;
85     uintptr_t jitFortBegin_ {0};
86     size_t jitFortSize_ {0};
87 
88     // Fort regions
89     static constexpr uint32_t FORT_BUF_ALIGN = 32;
90     static constexpr uint32_t FORT_BUF_ALIGN_LOG2 = base::MathHelper::GetIntLog2(FORT_BUF_ALIGN);
91     static constexpr size_t FORT_BUF_ADDR_MASK = FORT_BUF_ALIGN - 1;
92     static constexpr size_t MAX_JIT_FORT_REGIONS = JIT_FORT_REG_SPACE_MAX/DEFAULT_REGION_SIZE;
93     std::array<JitFortRegion *, MAX_JIT_FORT_REGIONS>regions_;
94     size_t nextFreeRegionIdx_ {0};
95     EcmaList<JitFortRegion> regionList_ {}; // regions in use by Jit Fort allocator
96 
97     MemDescPool *memDescPool_ {nullptr};
98 
99     bool freeListUpdated_ {false};  // use atomic if not mutext protected
100     Mutex mutex_;
101     Mutex liveJitCodeBlksLock_;
102     std::atomic<bool> isSweeping_ {false};
103     friend class HugeMachineCodeSpace;
104 };
105 
106 class JitFortGCBitset : public GCBitset {
107 public:
108     JitFortGCBitset() = default;
109     ~JitFortGCBitset() = default;
110 
111     NO_COPY_SEMANTIC(JitFortGCBitset);
112     NO_MOVE_SEMANTIC(JitFortGCBitset);
113 
114     template <typename Visitor>
115     void IterateMarkedBitsConst(uintptr_t regionAddr, size_t bitsetSize, Visitor visitor);
116     void MarkStartAddr(bool awaitInstall, uintptr_t startAddr, uint32_t index, uint32_t &word);
117     void MarkEndAddr(bool awaitInstall, uintptr_t endAddr, uint32_t index, uint32_t &word);
118 
WordCount(size_t size) const119     size_t WordCount(size_t size) const
120     {
121         return size >> BYTE_PER_WORD_LOG2;
122     }
123 
ClearMark(uintptr_t addr)124     inline void ClearMark(uintptr_t addr)
125     {
126         ClearBit((addr & DEFAULT_REGION_MASK) >> TAGGED_TYPE_SIZE_LOG);
127     }
128 
Test(uintptr_t addr)129     inline bool Test(uintptr_t addr)
130     {
131         return TestBit((addr & DEFAULT_REGION_MASK) >> TAGGED_TYPE_SIZE_LOG);
132     }
133 };
134 
135 class JitFortRegion : public Region {
136 public:
JitFortRegion(NativeAreaAllocator *allocator, uintptr_t allocateBase, uintptr_t end, RegionSpaceFlag spaceType, MemDescPool *pool)137     JitFortRegion(NativeAreaAllocator *allocator, uintptr_t allocateBase, uintptr_t end,
138         RegionSpaceFlag spaceType, MemDescPool *pool) : Region(allocator, allocateBase, end, spaceType),
139         memDescPool_(pool)
140     {
141         markGCBitset_ = new(reinterpret_cast<void *>(gcBitSet_)) JitFortGCBitset();
142         markGCBitset_->Clear(bitsetSize_);
143         InitializeFreeObjectSets();
144     }
145 
InitializeFreeObjectSets()146     void InitializeFreeObjectSets()
147     {
148         fortFreeObjectSets_ = Span<FreeObjectSet<MemDesc> *>(new FreeObjectSet<MemDesc>
149             *[FreeObjectList<MemDesc>::NumberOfSets()](), FreeObjectList<MemDesc>::NumberOfSets());
150     }
151 
DestroyFreeObjectSets()152     void DestroyFreeObjectSets()
153     {
154         for (auto set : fortFreeObjectSets_) {
155             delete set;
156         }
157         delete[] fortFreeObjectSets_.data();
158     }
159 
GetFreeObjectSet(SetType type)160     FreeObjectSet<MemDesc> *GetFreeObjectSet(SetType type)
161     {
162         // Thread safe
163         if (fortFreeObjectSets_[type] == nullptr) {
164             fortFreeObjectSets_[type] = new FreeObjectSet<MemDesc>(type, memDescPool_);
165         }
166         return fortFreeObjectSets_[type];
167     }
168 
LinkNext(JitFortRegion *next)169     inline void LinkNext(JitFortRegion *next)
170     {
171         next_ = next;
172     }
173 
GetNext() const174     inline JitFortRegion *GetNext() const
175     {
176         return next_;
177     }
178 
LinkPrev(JitFortRegion *prev)179     inline void LinkPrev(JitFortRegion *prev)
180     {
181         prev_ = prev;
182     }
183 
GetPrev() const184     inline JitFortRegion *GetPrev() const
185     {
186         return prev_;
187     }
188 
GetGCBitset()189     inline JitFortGCBitset *GetGCBitset()
190     {
191         return markGCBitset_;
192     }
193 
GetGCBitsetSize()194     inline size_t GetGCBitsetSize()
195     {
196         return bitsetSize_;
197     }
198 
AtomicMark(void *address)199     inline bool AtomicMark(void *address)
200     {
201         auto addrPtr = reinterpret_cast<uintptr_t>(address);
202         ASSERT(InRange(addrPtr));
203         return markGCBitset_->SetBit<AccessType::ATOMIC>(
204             (addrPtr & DEFAULT_REGION_MASK) >> TAGGED_TYPE_SIZE_LOG);
205     }
206 
207 private:
208     Span<FreeObjectSet<MemDesc> *> fortFreeObjectSets_;
209     JitFortRegion *next_ {nullptr};
210     JitFortRegion *prev_ {nullptr};
211     MemDescPool *memDescPool_ {nullptr};
212 
213     static constexpr int FORT_REGION_BITSET_SIZE = 4096;
214     size_t bitsetSize_ {FORT_REGION_BITSET_SIZE};
215     alignas(uint64_t) uint8_t gcBitSet_[FORT_REGION_BITSET_SIZE];
216     alignas(uint64_t) JitFortGCBitset *markGCBitset_ {nullptr};
217 };
218 
219 }  // namespace panda::ecmascript
220 #endif  // ECMASCRIPT_MEM_SPARSE_SPACE_H
221