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