• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_REGION_H
17 #define ECMASCRIPT_MEM_REGION_H
18 
19 #include "ecmascript/mem/free_object_list.h"
20 #include "ecmascript/mem/mem.h"
21 #include "mem/gc/bitmap.h"
22 #include "native_area_allocator.h"
23 
24 namespace panda {
25 using RangeBitmap = mem::MemBitmap<static_cast<size_t>(ecmascript::MemAlignment::MEM_ALIGN_OBJECT)>;
26 
27 namespace ecmascript {
28 class Space;
29 class Heap;
30 class RememberedSet;
31 class WorkerHelper;
32 
33 enum RegionFlags {
34     NEVER_EVACUATE = 1,
35     HAS_AGE_MARK = 1 << 1,
36     BELOW_AGE_MARK = 1 << 2,
37     IS_IN_YOUNG_GENERATION = 1 << 3,
38     IS_IN_SNAPSHOT_GENERATION = 1 << 4,
39     IS_HUGE_OBJECT = 1 << 5,
40     IS_IN_OLD_GENERATION = 1 << 6,
41     IS_IN_NON_MOVABLE_GENERATION = 1 << 7,
42     IS_IN_YOUNG_OR_OLD_GENERATION = IS_IN_YOUNG_GENERATION | IS_IN_OLD_GENERATION,
43     IS_IN_COLLECT_SET = 1 << 8,
44     IS_IN_NEW_TO_NEW_SET = 1 << 9,
45     IS_IN_YOUNG_OR_CSET_GENERATION = IS_IN_YOUNG_GENERATION | IS_IN_COLLECT_SET,
46     IS_INVALID = 1 << 10,
47 };
48 
49 #define REGION_OFFSET_LIST(V)                                                             \
50     V(BITMAP, BitMap, markBitmap_, FLAG, sizeof(uint32_t), sizeof(uint64_t))              \
51     V(OLDTONEWSET, OldToNewSet, oldToNewSet_, BITMAP, sizeof(uint32_t), sizeof(uint64_t))
52 
53 class Region {
54 public:
Region(Space * space,Heap * heap,uintptr_t allocateBase,uintptr_t begin,uintptr_t end,NativeAreaAllocator * nativeAreaAllocator)55     Region(Space *space, Heap *heap, uintptr_t allocateBase, uintptr_t begin,
56         uintptr_t end, NativeAreaAllocator* nativeAreaAllocator)
57         : flags_(0), space_(space), heap_(heap),
58         allocateBase_(allocateBase),
59         // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
60         begin_(begin),
61         end_(end),
62         highWaterMark_(end),
63         aliveObject_(0),
64         wasted_(0),
65         nativeAreaAllocator_(nativeAreaAllocator)
66     {
67         markBitmap_ = CreateMarkBitmap();
68     }
69     ~Region() = default;
70     NO_COPY_SEMANTIC(Region);
71     NO_MOVE_SEMANTIC(Region);
72 
Reset()73     void Reset()
74     {
75         flags_ = 0;
76         highWaterMark_ = end_;
77         if (memset_s(reinterpret_cast<void *>(begin_), GetSize(), 0, GetSize()) != EOK) {
78             UNREACHABLE();
79         }
80     }
81 
LinkNext(Region * next)82     void LinkNext(Region *next)
83     {
84         next_ = next;
85     }
86 
GetNext()87     Region *GetNext() const
88     {
89         return next_;
90     }
91 
LinkPrev(Region * prev)92     void LinkPrev(Region *prev)
93     {
94         prev_ = prev;
95     }
96 
GetPrev()97     Region *GetPrev() const
98     {
99         return prev_;
100     }
101 
GetBegin()102     uintptr_t GetBegin() const
103     {
104         return begin_;
105     }
106 
GetEnd()107     uintptr_t GetEnd() const
108     {
109         return end_;
110     }
111 
GetCapacity()112     size_t GetCapacity() const
113     {
114         return end_ - reinterpret_cast<uintptr_t>(this);
115     }
116 
GetSize()117     size_t GetSize() const
118     {
119         return end_ - begin_;
120     }
121 
122     inline void SetSpace(Space *space);
123 
GetHeap()124     Heap *GetHeap() const
125     {
126         return heap_;
127     }
128 
GetSpace()129     Space *GetSpace() const
130     {
131         return space_;
132     }
133 
ResetFlag()134     void ResetFlag()
135     {
136         flags_ = 0;
137     }
138 
SetFlag(RegionFlags flag)139     void SetFlag(RegionFlags flag)
140     {
141         flags_ |= flag;
142     }
143 
ClearFlag(RegionFlags flag)144     void ClearFlag(RegionFlags flag)
145     {
146         // NOLINTNEXTLINE(hicpp-signed-bitwise)
147         flags_ &= ~flag;
148     }
149 
IsFlagSet(RegionFlags flag)150     bool IsFlagSet(RegionFlags flag) const
151     {
152         return (flags_ & flag) != 0;
153     }
154 
GetMarkBitmap()155     RangeBitmap *GetMarkBitmap()
156     {
157         return markBitmap_;
158     }
159 
GetCrossRegionRememberedSet()160     RememberedSet *GetCrossRegionRememberedSet()
161     {
162         return crossRegionSet_;
163     }
164 
GetOldToNewRememberedSet()165     RememberedSet *GetOldToNewRememberedSet()
166     {
167         return oldToNewSet_;
168     }
169 
ObjectAddressToRange(TaggedObject * obj)170     static Region *ObjectAddressToRange(TaggedObject *obj)
171     {
172         return reinterpret_cast<Region *>(ToUintPtr(obj) & ~DEFAULT_REGION_MASK);
173     }
174 
ObjectAddressToRange(uintptr_t objAddress)175     static Region *ObjectAddressToRange(uintptr_t objAddress)
176     {
177         return reinterpret_cast<Region *>(objAddress & ~DEFAULT_REGION_MASK);
178     }
179 
InYoungGeneration()180     bool InYoungGeneration() const
181     {
182         return IsFlagSet(RegionFlags::IS_IN_YOUNG_GENERATION);
183     }
184 
InOldGeneration()185     bool InOldGeneration() const
186     {
187         return IsFlagSet(RegionFlags::IS_IN_OLD_GENERATION);
188     }
189 
InYoungAndOldGeneration()190     bool InYoungAndOldGeneration() const
191     {
192         return IsFlagSet(RegionFlags::IS_IN_YOUNG_OR_OLD_GENERATION);
193     }
194 
InHugeObjectGeneration()195     bool InHugeObjectGeneration() const
196     {
197         return IsFlagSet(RegionFlags::IS_HUGE_OBJECT);
198     }
199 
InYoungOrCSetGeneration()200     bool InYoungOrCSetGeneration() const
201     {
202         return IsFlagSet(RegionFlags::IS_IN_YOUNG_OR_CSET_GENERATION);
203     }
204 
InNewToNewSet()205     bool InNewToNewSet() const
206     {
207         return IsFlagSet(RegionFlags::IS_IN_NEW_TO_NEW_SET);
208     }
209 
InCollectSet()210     bool InCollectSet() const
211     {
212         return IsFlagSet(RegionFlags::IS_IN_COLLECT_SET);
213     }
214 
HasAgeMark()215     bool HasAgeMark() const
216     {
217         return IsFlagSet(RegionFlags::HAS_AGE_MARK);
218     }
219 
BelowAgeMark()220     bool BelowAgeMark() const
221     {
222         return IsFlagSet(RegionFlags::BELOW_AGE_MARK);
223     }
224 
InRange(uintptr_t address)225     bool InRange(uintptr_t address)
226     {
227         return address >= begin_ && address <= end_;
228     }
229 
CreateMarkBitmap()230     inline RangeBitmap *CreateMarkBitmap()
231     {
232         size_t heapSize = IsFlagSet(RegionFlags::IS_HUGE_OBJECT) ? LARGE_BITMAP_MIN_SIZE : GetCapacity();
233         // Only one huge object is stored in a region. The BitmapSize of a huge region will always be 8 Bytes.
234         size_t bitmapSize = RangeBitmap::GetBitMapSizeInByte(heapSize);
235         ASSERT(nativeAreaAllocator_ != nullptr);
236         auto bitmapData = const_cast<NativeAreaAllocator *>(nativeAreaAllocator_)->Allocate(bitmapSize);
237         auto *ret = new RangeBitmap(this, heapSize, bitmapData);
238         ret->ClearAllBits();
239         return ret;
240     }
241     inline RememberedSet *CreateRememberedSet();
242     inline RememberedSet *GetOrCreateCrossRegionRememberedSet();
243     inline RememberedSet *GetOrCreateOldToNewRememberedSet();
244     inline void DeleteMarkBitmap();
245     inline void DeleteCrossRegionRememberedSet();
246     inline void DeleteOldToNewRememberedSet();
247     inline void ClearMarkBitmap();
248     inline void ClearCrossRegionRememberedSet();
249     inline void InsertCrossRegionRememberedSet(uintptr_t addr);
250     inline void AtomicInsertCrossRegionRememberedSet(uintptr_t addr);
251     inline void InsertOldToNewRememberedSet(uintptr_t addr);
252     inline void AtomicInsertOldToNewRememberedSet(uintptr_t addr);
253 
GetAllocateBase()254     uintptr_t GetAllocateBase() const
255     {
256         return allocateBase_;
257     }
258 
259     size_t GetAllocatedBytes(uintptr_t top = 0)
260     {
261         ASSERT(top == 0 || InRange(top));
262         return (top == 0) ? (highWaterMark_ - begin_) : (top - begin_);
263     }
264 
SetHighWaterMark(uintptr_t mark)265     void SetHighWaterMark(uintptr_t mark)
266     {
267         ASSERT(InRange(mark));
268         highWaterMark_ = mark;
269     }
270 
SetCodeExecutableAndReadable()271     int SetCodeExecutableAndReadable()
272     {
273         // NOLINT(hicpp-signed-bitwise)
274         int res = mprotect(reinterpret_cast<void *>(allocateBase_), GetCapacity(), PROT_EXEC | PROT_READ | PROT_WRITE);
275         return res;
276     }
277 
InitializeSet()278     void InitializeSet()
279     {
280         sets_ = Span<FreeObjectSet *>(new FreeObjectSet *[FreeObjectList::NumberOfSets()](),
281             FreeObjectList::NumberOfSets());
282     }
283 
RebuildSet()284     void RebuildSet()
285     {
286         EnumerateSets([](FreeObjectSet *set) {
287             if (set != nullptr) {
288                 set->Rebuild();
289             }
290         });
291     }
292 
DestroySet()293     void DestroySet()
294     {
295         for (auto set : sets_) {
296             delete set;
297         }
298         delete[] sets_.data();
299     }
300 
GetFreeObjectSet(SetType type)301     FreeObjectSet *GetFreeObjectSet(SetType type)
302     {
303         // Thread safe
304         if (sets_[type] == nullptr) {
305             sets_[type] = new FreeObjectSet(type);
306         }
307         return sets_[type];
308     }
309 
310     template<class Callback>
EnumerateSets(Callback cb)311     void EnumerateSets(Callback cb)
312     {
313         for (auto set : sets_) {
314             cb(set);
315         }
316     }
317 
318     inline bool IsMarking() const;
319 
320     inline WorkerHelper *GetWorkList() const;
321 
IncrementAliveObjectSafe(size_t size)322     void IncrementAliveObjectSafe(size_t size)
323     {
324         ASSERT(aliveObject_ + size <= GetSize());
325         aliveObject_ += size;
326     }
327 
IncrementAliveObject(size_t size)328     void IncrementAliveObject(size_t size)
329     {
330         ASSERT(aliveObject_ + size <= GetSize());
331         aliveObject_.fetch_add(size, std::memory_order_relaxed);
332     }
333 
ResetAliveObject()334     void ResetAliveObject()
335     {
336         aliveObject_ = 0;
337     }
338 
AliveObject()339     size_t AliveObject() const
340     {
341         return aliveObject_;
342     }
343 
MostObjectAlive()344     bool MostObjectAlive() const
345     {
346         return aliveObject_ > MOST_OBJECT_ALIVE_THRESHOLD_PERCENT * GetSize();
347     }
348 
ResetWasted()349     void ResetWasted()
350     {
351         wasted_ = 0;
352     }
IncrementWasted(size_t size)353     void IncrementWasted(size_t size)
354     {
355         wasted_ += size;
356     }
GetWastedSize()357     size_t GetWastedSize()
358     {
359         return wasted_;
360     }
361 
362     static constexpr uint32_t GetOldToNewSetOffset(bool is32Bit = false)
363     {
364         return is32Bit ? REGION_OLDTONEWSET_OFFSET_32 : REGION_OLDTONEWSET_OFFSET_64;
365     }
366 
367     static constexpr uint32_t GetBitMapOffset(bool is32Bit = false)
368     {
369         return is32Bit ? REGION_BITMAP_OFFSET_32 : REGION_BITMAP_OFFSET_64;
370     }
371 
372     static constexpr uint32_t GetFlagOffset(bool is32Bit = false)
373     {
374         return is32Bit ? REGION_FLAG_OFFSET_32 : REGION_FLAG_OFFSET_64;
375     }
376 
377     #define REGION_OFFSET_MACRO(name, camelName, memberName, lastName, lastSize32, lastSize64)             \
378         static constexpr uint32_t REGION_##name##_OFFSET_32 = REGION_##lastName##_OFFSET_32 + (lastSize32); \
379         static constexpr uint32_t REGION_##name##_OFFSET_64 = REGION_##lastName##_OFFSET_64 + (lastSize64);
380     static constexpr uint32_t REGION_FLAG_OFFSET_32 = 0U;
381     static constexpr uint32_t REGION_FLAG_OFFSET_64 = 0U;
REGION_OFFSET_LIST(REGION_OFFSET_MACRO)382     REGION_OFFSET_LIST(REGION_OFFSET_MACRO)
383     #undef REGION_OFFSET_MACRO
384 
385     static constexpr bool CheckLayout()
386     {
387 #ifdef PANDA_TARGET_32
388         #define REGION_OFFSET_ASSET(name, camelName, memberName, lastName, lastSize32, lastSize64)         \
389         static_assert(MEMBER_OFFSET(Region, memberName) == (Get##camelName##Offset(true)));
390         REGION_OFFSET_LIST(REGION_OFFSET_ASSET)
391         static_assert(GetFlagOffset(true) == MEMBER_OFFSET(Region, flags_));
392         #undef REGION_OFFSET_ASSET
393 #endif
394 #ifdef PANDA_TARGET_64
395         #define REGION_OFFSET_ASSET(name, camelName, memberName, lastName, lastSize32, lastSize64)         \
396         static_assert(MEMBER_OFFSET(Region, memberName) == (Get##camelName##Offset(false)));
397         REGION_OFFSET_LIST(REGION_OFFSET_ASSET)
398         static_assert(GetFlagOffset(false) == MEMBER_OFFSET(Region, flags_));
399         #undef REGION_OFFSET_ASSET
400 #endif
401         return true;
402     }
403 private:
404     static constexpr double MOST_OBJECT_ALIVE_THRESHOLD_PERCENT = 0.8;
405     uintptr_t flags_;  // Memory alignment, only low 32bits are used now
406     RangeBitmap *markBitmap_ {nullptr};
407     RememberedSet *oldToNewSet_ {nullptr};
408     Space *space_;
409     Heap *heap_;
410 
411     uintptr_t allocateBase_;
412     uintptr_t begin_;
413     uintptr_t end_;
414     uintptr_t highWaterMark_;
415     std::atomic_size_t aliveObject_ {0};
416     Region *next_ {nullptr};
417     Region *prev_ {nullptr};
418 
419     RememberedSet *crossRegionSet_ {nullptr};
420     Span<FreeObjectSet *> sets_;
421     size_t wasted_;
422     os::memory::Mutex lock_;
423     NativeAreaAllocator* nativeAreaAllocator_ {nullptr};
424     friend class SnapShot;
425 };
426 
427 class BitmapHelper : public mem::Bitmap {
428 public:
429     static const size_t BITSPERWORD_64 = BITSPERBYTE * sizeof(uint64_t);
430     static const size_t BITSPERWORD_32 = BITSPERBYTE * sizeof(uint32_t);
431     static constexpr size_t LOG_BITSPERWORD_64 = panda::helpers::math::GetIntLog2(
432         static_cast<uint64_t>(BITSPERWORD_64));
433     static constexpr size_t LOG_BITSPERWORD_32 = panda::helpers::math::GetIntLog2(
434         static_cast<uint64_t>(BITSPERWORD_32));
435     NO_COPY_SEMANTIC(BitmapHelper);
436     NO_MOVE_SEMANTIC(BitmapHelper);
437     static constexpr uint32_t LogBitsPerWord(bool is32Bit = false)
438     {
439         return is32Bit ? LOG_BITSPERWORD_32 : LOG_BITSPERWORD_64;
440     }
CheckLayout()441     static constexpr bool CheckLayout()
442     {
443     #ifdef PANDA_TARGET_32
444         static_assert(LogBitsPerWord(true) == mem::Bitmap::LOG_BITSPERWORD);
445     #else
446         static_assert(LogBitsPerWord(false) == mem::Bitmap::LOG_BITSPERWORD);
447     #endif
448         return true;
449     }
450 };
451 static_assert(Region::CheckLayout());
452 static_assert(BitmapHelper::CheckLayout());
453 }  // namespace ecmascript
454 }  // namespace panda
455 
456 #endif  // ECMASCRIPT_MEM_REGION_H
457