1 /*
2  * Copyright (c) 2022-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_REGION_H
17 #define ECMASCRIPT_MEM_REGION_H
18 
19 #include <type_traits>
20 
21 #include "ecmascript/base/aligned_struct.h"
22 #include "ecmascript/base/asan_interface.h"
23 #include "ecmascript/js_tagged_value.h"
24 #include "ecmascript/mem/free_object_list.h"
25 #include "ecmascript/mem/gc_bitset.h"
26 #include "ecmascript/mem/remembered_set.h"
27 #include "ecmascript/mem/mem_common.h"
28 #include "ecmascript/platform/map.h"
29 
30 #include "ecmascript/platform/mutex.h"
31 
32 #include "securec.h"
33 
34 namespace panda {
35 namespace ecmascript {
36 class JSThread;
37 
38 enum RegionSpaceFlag {
39     UNINITIALIZED = 0,
40     // We should avoid using the lower 3 bits (bits 0 to 2).
41     // If ZAP_MEM is enabled, the value of the lower 3 bits conflicts with the INVALID_VALUE.
42 
43     // Bits 3 to 7 are reserved to denote the space where the region is located.
44     IN_EDEN_SPACE = 0x08,
45     IN_YOUNG_SPACE = 0x09,
46     IN_SNAPSHOT_SPACE = 0x0A,
47     IN_HUGE_OBJECT_SPACE = 0x0B,
48     IN_OLD_SPACE = 0x0C,
49     IN_NON_MOVABLE_SPACE = 0x0D,
50     IN_MACHINE_CODE_SPACE = 0x0E,
51     IN_READ_ONLY_SPACE = 0X0F,
52     IN_APPSPAWN_SPACE = 0x10,
53     IN_HUGE_MACHINE_CODE_SPACE = 0x11,
54     IN_SHARED_NON_MOVABLE = 0x12,
55     IN_SHARED_OLD_SPACE = 0x13,
56     IN_SHARED_APPSPAWN_SPACE = 0X14,
57     IN_SHARED_HUGE_OBJECT_SPACE = 0x15,
58     IN_SHARED_READ_ONLY_SPACE = 0x16,
59 
60     VALID_SPACE_MASK = 0xFF,
61 
62     GENERAL_YOUNG_BEGIN = IN_EDEN_SPACE,
63     GENERAL_YOUNG_END = IN_YOUNG_SPACE,
64     GENERAL_OLD_BEGIN = IN_SNAPSHOT_SPACE,
65     GENERAL_OLD_END = IN_HUGE_MACHINE_CODE_SPACE,
66     SHARED_SPACE_BEGIN = IN_SHARED_NON_MOVABLE,
67     SHARED_SPACE_END = IN_SHARED_READ_ONLY_SPACE,
68     SHARED_SWEEPABLE_SPACE_BEGIN = IN_SHARED_NON_MOVABLE,
69     SHARED_SWEEPABLE_SPACE_END = IN_SHARED_HUGE_OBJECT_SPACE,
70 
71     HEAP_SPACE_BEGIN = IN_EDEN_SPACE,
72     HEAP_SPACE_END = IN_SHARED_READ_ONLY_SPACE
73 };
74 
75 enum RegionGCFlags {
76     // We should avoid using the lower 3 bits (bits 0 to 2).
77     // If ZAP_MEM is enabled, the value of the lower 3 bits conflicts with the INVALID_VALUE.
78 
79     // Below flags are used for GC, and each flag has a dedicated bit starting from the 3rd bit.
80     NEVER_EVACUATE = 1 << 3,
81     HAS_AGE_MARK = 1 << 4,
82     BELOW_AGE_MARK = 1 << 5,
83     IN_COLLECT_SET = 1 << 6,
84     IN_NEW_TO_NEW_SET = 1 << 7,
85     // Bits 8 to 10 (the lower 3 bits for the next byte) are also excluded for the sake of
86     // INVALID_VALUE in ZAP_MEM.
87     HAS_BEEN_SWEPT = 1 << 11,
88     NEED_RELOCATE = 1 << 12,
89     // ONLY used for heap verification.
90     IN_INACTIVE_SEMI_SPACE = 1 << 13,
91 };
92 
93 // Currently only use for region in LinearSpace, to check if the region is allocated during concurrent marking.
94 enum class RegionTypeFlag : uint8_t {
95     DEFAULT = 0,
96     // We should avoid using the lower 3 bits (bits 0 to 2).
97     // If ZAP_MEM is enabled, the value of the lower 3 bits conflicts with the INVALID_VALUE.
98 
99     // Region is allocated before concurrent marking, but some new object may be allocated here
100     // during concurrent marking.
101     HALF_FRESH = 0x08,
102     // Region is allocated during concurrent marking.
103     FRESH = 0x09,
104 };
105 
106 enum RSetType {
107     OLD_TO_NEW,
108     LOCAL_TO_SHARE,
109 };
110 
ToSpaceTypeName(uint8_t space)111 static inline std::string ToSpaceTypeName(uint8_t space)
112 {
113     switch (space) {
114         case RegionSpaceFlag::IN_EDEN_SPACE:
115             return "eden space";
116         case RegionSpaceFlag::IN_YOUNG_SPACE:
117             return "young space";
118         case RegionSpaceFlag::IN_SNAPSHOT_SPACE:
119             return "snapshot space";
120         case RegionSpaceFlag::IN_HUGE_OBJECT_SPACE:
121             return "huge object space";
122         case RegionSpaceFlag::IN_OLD_SPACE:
123             return "old space";
124         case RegionSpaceFlag::IN_NON_MOVABLE_SPACE:
125             return "non movable space";
126         case RegionSpaceFlag::IN_MACHINE_CODE_SPACE:
127             return "machine code space";
128         case RegionSpaceFlag::IN_READ_ONLY_SPACE:
129             return "read only space";
130         case RegionSpaceFlag::IN_APPSPAWN_SPACE:
131             return "appspawn space";
132         case RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE:
133             return "huge machine code space";
134         case RegionSpaceFlag::IN_SHARED_NON_MOVABLE:
135             return "shared non movable space";
136         case RegionSpaceFlag::IN_SHARED_OLD_SPACE:
137             return "shared old space";
138         case RegionSpaceFlag::IN_SHARED_READ_ONLY_SPACE:
139             return "shared read only space";
140         case RegionSpaceFlag::IN_SHARED_HUGE_OBJECT_SPACE:
141             return "shared huge object space";
142         case RegionSpaceFlag::IN_SHARED_APPSPAWN_SPACE:
143             return "shared appspawn space";
144         default:
145             return "invalid space";
146     }
147 }
148 
149 // |---------------------------------------------------------------------------------------|
150 // |                                   Region (256 kb)                                     |
151 // |---------------------------------|--------------------------------|--------------------|
152 // |     Head (sizeof(Region))       |         Mark bitset (4kb)      |      Data          |
153 // |---------------------------------|--------------------------------|--------------------|
154 
155 class Region {
156 public:
Region(NativeAreaAllocator *allocator, uintptr_t allocateBase, uintptr_t begin, uintptr_t end, RegionSpaceFlag spaceType, RegionTypeFlag typeFlag)157     Region(NativeAreaAllocator *allocator, uintptr_t allocateBase, uintptr_t begin, uintptr_t end,
158         RegionSpaceFlag spaceType, RegionTypeFlag typeFlag)
159         : packedData_(begin, end, spaceType, typeFlag),
160           nativeAreaAllocator_(allocator),
161           allocateBase_(allocateBase),
162           end_(end),
163           highWaterMark_(end),
164           aliveObject_(0),
165           wasted_(0),
166           snapshotData_(0) {}
167 
168     // JitFort space is divided into regions (JitForRegion) to enable
169     // reusing free_object_list and free_object_set operations for
170     // JitFort space, and GC marking actually happens in corresponding
171     // MachineCode objects where JitFort space is allocated to. So no
172     // gc mark bits needed in JitFortRegions.
Region(NativeAreaAllocator *allocator, uintptr_t allocateBase, uintptr_t end, RegionSpaceFlag spaceType)173     Region(NativeAreaAllocator *allocator, uintptr_t allocateBase, uintptr_t end,
174         RegionSpaceFlag spaceType)
175         : packedData_(allocateBase, spaceType), // no markGCBitset_ for JitFort
176           nativeAreaAllocator_(allocator),
177           allocateBase_(allocateBase),
178           end_(end),
179           highWaterMark_(end),
180           aliveObject_(0),
181           wasted_(0),
182           snapshotData_(0) {}
183 
184     ~Region() = default;
185 
186     NO_COPY_SEMANTIC(Region);
187     NO_MOVE_SEMANTIC(Region);
188 
189     enum RegionSpaceKind { InYoung, InGeneralOld, Other };
190 
191     template <RegionSpaceKind kind>
192     class Updater final {
193     public:
Updater(uintptr_t updateAddress, Region& region)194         Updater(uintptr_t updateAddress, Region& region)
195             : bitsetUpdater_(updateAddress),
196               region_(region)
197         {
198         }
199 
200         NO_COPY_SEMANTIC(Updater);
201 
~Updater()202         ARK_INLINE ~Updater()
203         {
204             Flush();
205         }
206 
UpdateLocalToShare()207         ARK_INLINE void UpdateLocalToShare()
208         {
209             bitsetUpdater_.Update(LocalToShareIdx);
210         }
211 
212         template <RegionSpaceKind T = kind, std::enable_if_t<T == InYoung, int>  = 0>
UpdateNewToEden()213         ARK_INLINE void UpdateNewToEden()
214         {
215             bitsetUpdater_.Update(NewToEdenIdx);
216         }
217 
218         template <RegionSpaceKind T = kind, std::enable_if_t<T == InGeneralOld, int>  = 0>
UpdateOldToNew()219         ARK_INLINE void UpdateOldToNew()
220         {
221             bitsetUpdater_.Update(OldToNewIdx);
222         }
223 
Next()224         ARK_INLINE void Next()
225         {
226             if (bitsetUpdater_.Next()) {
227                 Flush();
228             }
229         }
230 
231     private:
232         ARK_INLINE void Consume(size_t idx, uintptr_t updateAddress, uint32_t mask);
233 
234         ARK_INLINE void Flush();
235 
CalculateBitSetNum()236         static constexpr size_t CalculateBitSetNum()
237         {
238             constexpr size_t InYoungBitSetNum = 2;
239             constexpr size_t InGeneralOldBitSetNum = 2;
240             constexpr size_t OtherBitSetNum = 1;
241             switch (kind) {
242                 case InYoung:
243                     return InYoungBitSetNum;
244                 case InGeneralOld:
245                     return InGeneralOldBitSetNum;
246                 case Other:
247                     return OtherBitSetNum;
248             }
249             return 0;
250         }
251 
252         static constexpr size_t BitSetNum = CalculateBitSetNum();
253         static constexpr size_t LocalToShareIdx = 0;
254         static constexpr size_t NewToEdenIdx = 1; // NewToEden and OldToNew can't be used at same time.
255         static constexpr size_t OldToNewIdx = 1;
256         GCBitSetUpdater<BitSetNum> bitsetUpdater_;
257         Region& region_;
258     };
259 
Initialize()260     void Initialize()
261     {
262         lock_ = new Mutex();
263         if (InSparseSpace()) {
264             InitializeFreeObjectSets();
265         }
266     }
267 
LinkNext(Region *next)268     void LinkNext(Region *next)
269     {
270         next_ = next;
271     }
272 
GetNext() const273     Region *GetNext() const
274     {
275         return next_;
276     }
277 
LinkPrev(Region *prev)278     void LinkPrev(Region *prev)
279     {
280         prev_ = prev;
281     }
282 
GetPrev() const283     Region *GetPrev() const
284     {
285         return prev_;
286     }
287 
GetBegin() const288     uintptr_t GetBegin() const
289     {
290         return packedData_.begin_;
291     }
292 
GetEnd() const293     uintptr_t GetEnd() const
294     {
295         return end_;
296     }
297 
GetHighWaterMark() const298     uintptr_t GetHighWaterMark() const
299     {
300         return highWaterMark_;
301     }
302 
GetCapacity() const303     size_t GetCapacity() const
304     {
305         return end_ - allocateBase_;
306     }
307 
GetSize() const308     size_t GetSize() const
309     {
310         return end_ - packedData_.begin_;
311     }
312 
IsGCFlagSet(RegionGCFlags flag) const313     bool IsGCFlagSet(RegionGCFlags flag) const
314     {
315         return (packedData_.flags_.gcFlags_ & flag) == flag;
316     }
317 
SetGCFlag(RegionGCFlags flag)318     void SetGCFlag(RegionGCFlags flag)
319     {
320         packedData_.flags_.gcFlags_ |= flag;
321     }
322 
ClearGCFlag(RegionGCFlags flag)323     void ClearGCFlag(RegionGCFlags flag)
324     {
325         // NOLINTNEXTLINE(hicpp-signed-bitwise)
326         packedData_.flags_.gcFlags_ &= ~flag;
327     }
328 
GetSpaceTypeName()329     std::string GetSpaceTypeName()
330     {
331         return ToSpaceTypeName(packedData_.flags_.spaceFlag_);
332     }
333 
GetSpaceType() const334     uint8_t GetSpaceType() const
335     {
336         return packedData_.flags_.spaceFlag_;
337     }
338 
339     // Mark bitset
340     GCBitset *GetMarkGCBitset() const;
341     bool AtomicMark(void *address);
342     // Objects in fresh region should only mark in JS Thread.
343     bool NonAtomicMark(void *address);
344     void ClearMark(void *address);
345     bool Test(void *addr) const;
346     bool Test(uintptr_t addr) const;
347     // ONLY used for heap verification.
348     bool TestNewToEden(uintptr_t addr);
349     bool TestOldToNew(uintptr_t addr);
350     bool TestLocalToShare(uintptr_t addr);
351     template <typename Visitor>
352     void IterateAllMarkedBits(Visitor visitor) const;
353     void ClearMarkGCBitset();
354     // local to share remembered set
355     bool HasLocalToShareRememberedSet() const;
356     RememberedSet *ExtractLocalToShareRSet();
357     void InsertLocalToShareRSet(uintptr_t addr);
358     template<RegionSpaceKind kind>
359     Updater<kind> GetBatchRSetUpdater(uintptr_t addr);
360     void AtomicInsertLocalToShareRSet(uintptr_t addr);
361     void ClearLocalToShareRSetInRange(uintptr_t start, uintptr_t end);
362     void AtomicClearLocalToShareRSetInRange(uintptr_t start, uintptr_t end);
363     void AtomicClearSweepingLocalToShareRSetInRange(uintptr_t start, uintptr_t end);
364     template <typename Visitor>
365     void IterateAllLocalToShareBits(Visitor visitor);
366     void DeleteLocalToShareRSet();
367     void DeleteSweepingLocalToShareRSet();
368     // Cross region remembered set
369     void InsertCrossRegionRSet(uintptr_t addr);
370     void AtomicInsertCrossRegionRSet(uintptr_t addr);
371     template <typename Visitor>
372     void IterateAllCrossRegionBits(Visitor visitor) const;
373     void ClearCrossRegionRSet();
374     void ClearCrossRegionRSetInRange(uintptr_t start, uintptr_t end);
375     void AtomicClearCrossRegionRSetInRange(uintptr_t start, uintptr_t end);
376     void DeleteCrossRegionRSet();
377     // New to eden remembered set
378     void InsertNewToEdenRSet(uintptr_t addr);
379     void AtomicInsertNewToEdenRSet(uintptr_t addr);
380     void ClearNewToEdenRSet(uintptr_t addr);
381     // Old to new remembered set
382     void InsertOldToNewRSet(uintptr_t addr);
383     void ClearOldToNewRSet(uintptr_t addr);
384 
385     template <typename Visitor>
386     void IterateAllNewToEdenBits(Visitor visitor);
387     template <typename Visitor>
388     void IterateAllOldToNewBits(Visitor visitor);
389     RememberedSet* GetNewToEdenRSet();
390     void ClearNewToEdenRSet();
391     void ClearNewToEdenRSetInRange(uintptr_t start, uintptr_t end);
392     void DeleteNewToEdenRSet();
393     void ClearOldToNewRSet();
394     void ClearOldToNewRSetInRange(uintptr_t start, uintptr_t end);
395     void DeleteOldToNewRSet();
396 
397     void AtomicClearSweepingOldToNewRSetInRange(uintptr_t start, uintptr_t end);
398     void ClearSweepingOldToNewRSetInRange(uintptr_t start, uintptr_t end);
399     void DeleteSweepingOldToNewRSet();
400     template <typename Visitor>
401     void AtomicIterateAllSweepingRSetBits(Visitor visitor);
402     template <typename Visitor>
403     void IterateAllSweepingRSetBits(Visitor visitor);
404 
ObjectAddressToRange(TaggedObject *obj)405     static Region *ObjectAddressToRange(TaggedObject *obj)
406     {
407         return reinterpret_cast<Region *>(ToUintPtr(obj) & ~DEFAULT_REGION_MASK);
408     }
409 
ObjectAddressToRange(uintptr_t objAddress)410     static Region *ObjectAddressToRange(uintptr_t objAddress)
411     {
412         return reinterpret_cast<Region *>(objAddress & ~DEFAULT_REGION_MASK);
413     }
414 
GetRegionAvailableSize()415     static size_t GetRegionAvailableSize()
416     {
417         size_t regionHeaderSize = AlignUp(sizeof(Region), static_cast<size_t>(MemAlignment::MEM_ALIGN_REGION));
418         size_t bitsetSize = GCBitset::SizeOfGCBitset(DEFAULT_REGION_SIZE - regionHeaderSize);
419         return DEFAULT_REGION_SIZE - regionHeaderSize - bitsetSize;
420     }
421 
ClearMembers()422     void ClearMembers()
423     {
424         if (lock_ != nullptr) {
425             delete lock_;
426             lock_ = nullptr;
427         }
428     }
429 
Invalidate()430     void Invalidate()
431     {
432         ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<void *>(GetBegin()), GetSize());
433         packedData_.flags_.spaceFlag_ = RegionSpaceFlag::UNINITIALIZED;
434     }
435 
436     uint8_t GetRegionSpaceFlag();
437 
SetRegionSpaceFlag(RegionSpaceFlag flag)438     void SetRegionSpaceFlag(RegionSpaceFlag flag)
439     {
440         packedData_.flags_.spaceFlag_ = flag;
441     }
InEdenSpace() const442     bool InEdenSpace() const
443     {
444         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_EDEN_SPACE;
445     }
446 
InYoungSpace() const447     bool InYoungSpace() const
448     {
449         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_YOUNG_SPACE;
450     }
451 
InOldSpace() const452     bool InOldSpace() const
453     {
454         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_OLD_SPACE;
455     }
456 
InYoungOrOldSpace() const457     bool InYoungOrOldSpace() const
458     {
459         return InGeneralNewSpace() || InOldSpace();
460     }
461 
InGeneralNewSpace() const462     bool InGeneralNewSpace() const
463     {
464         auto flag = packedData_.flags_.spaceFlag_;
465         return flag >= RegionSpaceFlag::GENERAL_YOUNG_BEGIN && flag <= RegionSpaceFlag::GENERAL_YOUNG_END;
466     }
467 
InGeneralOldSpace() const468     bool InGeneralOldSpace() const
469     {
470         ASSERT(packedData_.flags_.spaceFlag_ != 0);
471         auto flag = packedData_.flags_.spaceFlag_;
472         return flag >= RegionSpaceFlag::GENERAL_OLD_BEGIN && flag <= RegionSpaceFlag::GENERAL_OLD_END;
473     }
474 
InHugeObjectSpace() const475     bool InHugeObjectSpace() const
476     {
477         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_HUGE_OBJECT_SPACE;
478     }
479 
InMachineCodeSpace() const480     bool InMachineCodeSpace() const
481     {
482         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_MACHINE_CODE_SPACE;
483     }
484 
InHugeMachineCodeSpace() const485     bool InHugeMachineCodeSpace() const
486     {
487         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE;
488     }
489 
InNonMovableSpace() const490     bool InNonMovableSpace() const
491     {
492         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_NON_MOVABLE_SPACE;
493     }
494 
InSnapshotSpace() const495     bool InSnapshotSpace() const
496     {
497         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SNAPSHOT_SPACE;
498     }
499 
InReadOnlySpace() const500     bool InReadOnlySpace() const
501     {
502         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_READ_ONLY_SPACE;
503     }
504 
InSharedOldSpace() const505     bool InSharedOldSpace() const
506     {
507         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SHARED_OLD_SPACE;
508     }
509 
InSharedNonMovableSpace() const510     bool InSharedNonMovableSpace() const
511     {
512         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SHARED_NON_MOVABLE;
513     }
514 
InSharedHugeObjectSpace() const515     bool InSharedHugeObjectSpace() const
516     {
517         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SHARED_HUGE_OBJECT_SPACE;
518     }
519 
InSharedReadOnlySpace() const520     bool InSharedReadOnlySpace() const
521     {
522         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SHARED_READ_ONLY_SPACE;
523     }
524 
InSharedAppSpawnSpace() const525     bool InSharedAppSpawnSpace() const
526     {
527         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SHARED_APPSPAWN_SPACE;
528     }
529 
InAppSpawnSpace() const530     bool InAppSpawnSpace() const
531     {
532         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_APPSPAWN_SPACE;
533     }
534 
535     // Not including shared read only space.
InSharedSweepableSpace() const536     bool InSharedSweepableSpace() const
537     {
538         auto flag = packedData_.flags_.spaceFlag_;
539         return flag >= RegionSpaceFlag::SHARED_SWEEPABLE_SPACE_BEGIN &&
540                flag <= RegionSpaceFlag::SHARED_SWEEPABLE_SPACE_END;
541     }
542 
InSharedHeap() const543     bool InSharedHeap() const
544     {
545         auto flag = packedData_.flags_.spaceFlag_;
546         return flag >= RegionSpaceFlag::SHARED_SPACE_BEGIN && flag <= RegionSpaceFlag::SHARED_SPACE_END;
547     }
548 
InSparseSpace() const549     bool InSparseSpace() const
550     {
551         auto flag = packedData_.flags_.spaceFlag_;
552         switch (flag) {
553             case RegionSpaceFlag::IN_OLD_SPACE:
554             case RegionSpaceFlag::IN_NON_MOVABLE_SPACE:
555             case RegionSpaceFlag::IN_MACHINE_CODE_SPACE:
556             case RegionSpaceFlag::IN_APPSPAWN_SPACE:
557             case RegionSpaceFlag::IN_SHARED_NON_MOVABLE:
558             case RegionSpaceFlag::IN_SHARED_OLD_SPACE:
559                 return true;
560             default:
561                 return false;
562         }
563     }
564 
InHeapSpace() const565     bool InHeapSpace() const
566     {
567         uint8_t space = packedData_.flags_.spaceFlag_;
568         return space >= RegionSpaceFlag::HEAP_SPACE_BEGIN && space <= RegionSpaceFlag::HEAP_SPACE_END;
569     }
570 
InCollectSet() const571     bool InCollectSet() const
572     {
573         return IsGCFlagSet(RegionGCFlags::IN_COLLECT_SET);
574     }
575 
InGeneralNewSpaceOrCSet() const576     bool InGeneralNewSpaceOrCSet() const
577     {
578         return InGeneralNewSpace() || InCollectSet();
579     }
580 
InNewToNewSet() const581     bool InNewToNewSet() const
582     {
583         return IsGCFlagSet(RegionGCFlags::IN_NEW_TO_NEW_SET);
584     }
585 
HasAgeMark() const586     bool HasAgeMark() const
587     {
588         return IsGCFlagSet(RegionGCFlags::HAS_AGE_MARK);
589     }
590 
BelowAgeMark() const591     bool BelowAgeMark() const
592     {
593         return IsGCFlagSet(RegionGCFlags::BELOW_AGE_MARK);
594     }
595 
NeedRelocate() const596     bool NeedRelocate() const
597     {
598         return IsGCFlagSet(RegionGCFlags::NEED_RELOCATE);
599     }
600 
601     // ONLY used for heap verification.
InInactiveSemiSpace() const602     bool InInactiveSemiSpace() const
603     {
604         return IsGCFlagSet(RegionGCFlags::IN_INACTIVE_SEMI_SPACE);
605     }
606 
607     // ONLY used for heap verification.
InActiveSemiSpace() const608     bool InActiveSemiSpace() const
609     {
610         return InYoungSpace() && !InInactiveSemiSpace();
611     }
612 
GetRegionTypeFlag() const613     RegionTypeFlag GetRegionTypeFlag() const
614     {
615         return packedData_.typeFlag_;
616     }
617 
SetRegionTypeFlag(RegionTypeFlag typeFlag)618     void SetRegionTypeFlag(RegionTypeFlag typeFlag)
619     {
620         packedData_.typeFlag_ = typeFlag;
621     }
622 
ResetRegionTypeFlag()623     void ResetRegionTypeFlag()
624     {
625         SetRegionTypeFlag(RegionTypeFlag::DEFAULT);
626     }
627 
IsFreshRegion() const628     bool IsFreshRegion() const
629     {
630         return GetRegionTypeFlag() == RegionTypeFlag::FRESH;
631     }
632 
IsHalfFreshRegion() const633     bool IsHalfFreshRegion() const
634     {
635         return GetRegionTypeFlag() == RegionTypeFlag::HALF_FRESH;
636     }
637 
638     // ONLY used for heap verification.
SetInactiveSemiSpace()639     void SetInactiveSemiSpace()
640     {
641         SetGCFlag(RegionGCFlags::IN_INACTIVE_SEMI_SPACE);
642     }
643 
644     // ONLY used for heap verification.
ResetInactiveSemiSpace()645     void ResetInactiveSemiSpace()
646     {
647         ClearGCFlag(RegionGCFlags::IN_INACTIVE_SEMI_SPACE);
648     }
649 
SetSwept()650     void SetSwept()
651     {
652         SetGCFlag(RegionGCFlags::HAS_BEEN_SWEPT);
653     }
654 
ResetSwept()655     void ResetSwept()
656     {
657         ClearGCFlag(RegionGCFlags::HAS_BEEN_SWEPT);
658     }
659 
InRange(uintptr_t address) const660     bool InRange(uintptr_t address) const
661     {
662         return address >= packedData_.begin_ && address <= end_;
663     }
664 
GetAllocateBase() const665     uintptr_t GetAllocateBase() const
666     {
667         return allocateBase_;
668     }
669 
GetAllocatedBytes(uintptr_t top = 0)670     size_t GetAllocatedBytes(uintptr_t top = 0)
671     {
672         ASSERT(top == 0 || InRange(top));
673         return (top == 0) ? (highWaterMark_ - packedData_.begin_) : (top - packedData_.begin_);
674     }
675 
SetHighWaterMark(uintptr_t mark)676     void SetHighWaterMark(uintptr_t mark)
677     {
678         ASSERT(InRange(mark));
679         highWaterMark_ = mark;
680     }
681 
SetReadOnlyAndMarked()682     void SetReadOnlyAndMarked()
683     {
684         packedData_.markGCBitset_->SetAllBits(packedData_.bitsetSize_);
685         PageProtect(reinterpret_cast<void *>(allocateBase_), GetCapacity(), PAGE_PROT_READ);
686     }
687 
ClearReadOnly()688     void ClearReadOnly()
689     {
690         PageProtect(reinterpret_cast<void *>(allocateBase_), GetCapacity(), PAGE_PROT_READWRITE);
691     }
692 
InitializeFreeObjectSets()693     void InitializeFreeObjectSets()
694     {
695         FreeObjectSet<FreeObject> **sets = new FreeObjectSet<FreeObject> *[FreeObjectList<FreeObject>::NumberOfSets()];
696         for (int i = 0; i < FreeObjectList<FreeObject>::NumberOfSets(); i++) {
697             sets[i] = new FreeObjectSet<FreeObject>(i);
698         }
699         freeObjectSets_ = Span<FreeObjectSet<FreeObject> *>(sets, FreeObjectList<FreeObject>::NumberOfSets());
700     }
701 
DestroyFreeObjectSets()702     void DestroyFreeObjectSets()
703     {
704         for (int i = 0; i < FreeObjectList<FreeObject>::NumberOfSets(); i++) {
705             delete freeObjectSets_[i];
706             freeObjectSets_[i] = nullptr;
707         }
708         delete[] freeObjectSets_.data();
709     }
710 
GetFreeObjectSet(SetType type)711     FreeObjectSet<FreeObject> *GetFreeObjectSet(SetType type)
712     {
713         // Thread safe
714         if (freeObjectSets_[type] == nullptr) {
715             freeObjectSets_[type] = new FreeObjectSet<FreeObject>(type);
716         }
717         return freeObjectSets_[type];
718     }
719 
720     template<class Callback>
EnumerateFreeObjectSets(Callback cb)721     void EnumerateFreeObjectSets(Callback cb)
722     {
723         for (auto set : freeObjectSets_) {
724             cb(set);
725         }
726     }
727 
728     template<class Callback>
REnumerateFreeObjectSets(Callback cb)729     void REnumerateFreeObjectSets(Callback cb)
730     {
731         auto last = freeObjectSets_.crbegin();
732         auto first = freeObjectSets_.crend();
733         for (; last != first; last++) {
734             if (!cb(*last)) {
735                 break;
736             }
737         }
738     }
739 
IncreaseAliveObjectSafe(size_t size)740     void IncreaseAliveObjectSafe(size_t size)
741     {
742         ASSERT(aliveObject_ + size <= GetSize());
743         aliveObject_ += size;
744     }
745 
IncreaseAliveObject(size_t size)746     void IncreaseAliveObject(size_t size)
747     {
748         aliveObject_.fetch_add(size, std::memory_order_relaxed);
749     }
750 
SetRegionAliveSize()751     void SetRegionAliveSize()
752     {
753         gcAliveSize_ = aliveObject_;
754     }
755 
ResetAliveObject()756     void ResetAliveObject()
757     {
758         aliveObject_ = 0;
759     }
760 
AliveObject() const761     size_t AliveObject() const
762     {
763         return aliveObject_.load(std::memory_order_relaxed);
764     }
765 
GetGCAliveSize() const766     size_t GetGCAliveSize() const
767     {
768         return gcAliveSize_;
769     }
770 
MostObjectAlive() const771     bool MostObjectAlive() const
772     {
773         return aliveObject_ > MOST_OBJECT_ALIVE_THRESHOLD_PERCENT * GetSize();
774     }
775 
BelowCompressThreasholdAlive() const776     bool BelowCompressThreasholdAlive() const
777     {
778         return gcAliveSize_ < COMPRESS_THREASHOLD_PERCENT * GetSize();
779     }
780 
ResetWasted()781     void ResetWasted()
782     {
783         wasted_ = 0;
784     }
785 
IncreaseWasted(uint64_t size)786     void IncreaseWasted(uint64_t size)
787     {
788         wasted_ += size;
789     }
790 
GetWastedSize()791     uint64_t GetWastedSize()
792     {
793         return wasted_;
794     }
795 
GetSnapshotData()796     uint64_t GetSnapshotData()
797     {
798         return snapshotData_;
799     }
800 
SetSnapshotData(uint64_t value)801     void SetSnapshotData(uint64_t value)
802     {
803         snapshotData_ = value;
804     }
805 
SwapOldToNewRSetForCS()806     void SwapOldToNewRSetForCS()
807     {
808         sweepingOldToNewRSet_ = packedData_.oldToNewSet_;
809         packedData_.oldToNewSet_ = nullptr;
810     }
811 
SwapLocalToShareRSetForCS()812     void SwapLocalToShareRSetForCS()
813     {
814         sweepingLocalToShareRSet_ = packedData_.localToShareSet_;
815         packedData_.localToShareSet_ = nullptr;
816     }
817 
SetLocalHeap(uintptr_t localHeap)818     void SetLocalHeap(uintptr_t localHeap)
819     {
820         ASSERT(localHeap != (uintptr_t)nullptr);
821         localHeap_ = localHeap;
822     }
823 
GetLocalHeap(void)824     uintptr_t GetLocalHeap(void)
825     {
826         return localHeap_;
827     }
828 
829     // should call in js-thread
830     void MergeOldToNewRSetForCS();
831     void MergeLocalToShareRSetForCS();
832 
833     // should call in daemon-thread, or in js-thread in RUNNING state
834     void MergeLocalToShareRSetForCM(RememberedSet *set);
835 
836     struct alignas(JSTaggedValue::TaggedTypeSize()) PackedPtr : public base::AlignedPointer {
837         uint8_t spaceFlag_;
838         uint16_t  gcFlags_;
839     };
840 
841     struct PackedData : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
842                                                  base::AlignedPointer,
843                                                  base::AlignedPointer,
844                                                  base::AlignedPointer,
845                                                  base::AlignedPointer,
846                                                  base::AlignedPointer,
847                                                  base::AlignedPointer,
848                                                  base::AlignedSize> {
849         enum class Index : size_t {
850             FlagsIndex = 0,
851             TypeFlagIndex,
852             MarkGCBitSetIndex,
853             OldToNewSetIndex,
854             LocalToShareSetIndex,
855             BeginIndex,
856             BitSetSizeIndex,
857             NumOfMembers
858         };
859 
860         static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
861 
PackedDatapanda::ecmascript::Region::PackedData862         inline PackedData(uintptr_t begin, uintptr_t end, RegionSpaceFlag spaceType, RegionTypeFlag typeFlag)
863         {
864             flags_.spaceFlag_ = spaceType;
865             flags_.gcFlags_ = 0;
866             typeFlag_ = typeFlag;
867             bitsetSize_ = (spaceType == RegionSpaceFlag::IN_HUGE_OBJECT_SPACE ||
868                            spaceType == RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE ||
869                            spaceType == RegionSpaceFlag::IN_SHARED_HUGE_OBJECT_SPACE) ?
870                 GCBitset::BYTE_PER_WORD : GCBitset::SizeOfGCBitset(end - begin);
871             markGCBitset_ = new (ToVoidPtr(begin)) GCBitset();
872             markGCBitset_->Clear(bitsetSize_);
873             begin_ = AlignUp(begin + bitsetSize_, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
874             // The object region marked with poison until it is allocated if is_asan is true
875 #ifdef ARK_ASAN_ON
876             ASAN_POISON_MEMORY_REGION(reinterpret_cast<void *>(begin_), (end - begin_));
877 #endif
878         }
879 
PackedDatapanda::ecmascript::Region::PackedData880         inline PackedData(uintptr_t begin, RegionSpaceFlag spaceType)
881         {
882             flags_.spaceFlag_ = spaceType;
883             flags_.gcFlags_ = 0;
884             typeFlag_ = RegionTypeFlag::DEFAULT;
885             // no markGCBitset
886             begin_ = begin;
887             markGCBitset_ = nullptr;
888         }
889 
GetFlagsOffsetpanda::ecmascript::Region::PackedData890         static size_t GetFlagsOffset(bool isArch32)
891         {
892             return GetOffset<static_cast<size_t>(Index::FlagsIndex)>(isArch32);
893         }
894 
GetTypeFlagOffsetpanda::ecmascript::Region::PackedData895         static size_t GetTypeFlagOffset(bool isArch32)
896         {
897             return GetOffset<static_cast<size_t>(Index::TypeFlagIndex)>(isArch32);
898         }
899 
GetGCBitsetOffsetpanda::ecmascript::Region::PackedData900         static size_t GetGCBitsetOffset(bool isArch32)
901         {
902             return GetOffset<static_cast<size_t>(Index::MarkGCBitSetIndex)>(isArch32);
903         }
904 
GetNewToEdenSetOffsetpanda::ecmascript::Region::PackedData905         static size_t GetNewToEdenSetOffset(bool isArch32)
906         {
907             // NewToEdenRSet is Union with OldToNewRSet
908             return GetOffset<static_cast<size_t>(Index::OldToNewSetIndex)>(isArch32);
909         }
910 
GetOldToNewSetOffsetpanda::ecmascript::Region::PackedData911         static size_t GetOldToNewSetOffset(bool isArch32)
912         {
913             return GetOffset<static_cast<size_t>(Index::OldToNewSetIndex)>(isArch32);
914         }
915 
GetLocalToShareSetOffsetpanda::ecmascript::Region::PackedData916         static size_t GetLocalToShareSetOffset(bool isArch32)
917         {
918             return GetOffset<static_cast<size_t>(Index::LocalToShareSetIndex)>(isArch32);
919         }
920 
GetBeginOffsetpanda::ecmascript::Region::PackedData921         static size_t GetBeginOffset(bool isArch32)
922         {
923             return GetOffset<static_cast<size_t>(Index::BeginIndex)>(isArch32);
924         }
925 
926         alignas(EAS) PackedPtr flags_;
927         // Use different UIntPtr from flags_ to prevent the potential data race.
928         // Be careful when storing to this value, currently this is only from JS_Thread during ConcurrentMarking,
929         // or from GC_Thread during GC ClearTask.
930         alignas(EAS) RegionTypeFlag typeFlag_;
931         alignas(EAS) GCBitset *markGCBitset_ {nullptr};
932         // OldToNewRSet only for general OldSpace, NewToEdenRSet only for YoungSpace. Their pointers can union
933         union {
934             alignas(EAS) RememberedSet *oldToNewSet_ {nullptr};
935             alignas(EAS) RememberedSet *newToEdenSet_;
936         };
937         alignas(EAS) RememberedSet *localToShareSet_ {nullptr};
938         alignas(EAS) uintptr_t begin_ {0};
939         alignas(EAS) size_t bitsetSize_ {0};
940     };
941     STATIC_ASSERT_EQ_ARCH(sizeof(PackedData), PackedData::SizeArch32, PackedData::SizeArch64);
942 
943     static constexpr double MOST_OBJECT_ALIVE_THRESHOLD_PERCENT = 0.8;
944     static constexpr double AVERAGE_REGION_EVACUATE_SIZE = MOST_OBJECT_ALIVE_THRESHOLD_PERCENT *
945                                                            DEFAULT_REGION_SIZE / 2;  // 2 means half
946 private:
947     static constexpr double COMPRESS_THREASHOLD_PERCENT = 0.1;
948 
949     RememberedSet *CreateRememberedSet();
950     RememberedSet *GetOrCreateCrossRegionRememberedSet();
951     RememberedSet *GetOrCreateNewToEdenRememberedSet();
952     RememberedSet *GetOrCreateOldToNewRememberedSet();
953     RememberedSet *GetOrCreateLocalToShareRememberedSet();
954 
955     inline RememberedSet *CreateNewToEdenRememberedSet();
956     inline RememberedSet *CreateOldToNewRememberedSet();
957     inline RememberedSet *CreateLocalToShareRememberedSet();
958 
959     PackedData packedData_;
960     NativeAreaAllocator *nativeAreaAllocator_;
961 
962     uintptr_t allocateBase_;
963     uintptr_t end_;
964     uintptr_t highWaterMark_;
965     std::atomic_size_t aliveObject_ {0};
966     size_t gcAliveSize_ {0};
967     Region *next_ {nullptr};
968     Region *prev_ {nullptr};
969 
970     RememberedSet *crossRegionSet_ {nullptr};
971     RememberedSet *sweepingOldToNewRSet_ {nullptr};
972     RememberedSet *sweepingLocalToShareRSet_ {nullptr};
973     Span<FreeObjectSet<FreeObject> *> freeObjectSets_;
974     Mutex *lock_ {nullptr};
975     uint64_t wasted_;
976     // snapshotdata_ is used to encode the region for snapshot. Its upper 32 bits are used to store the size of
977     // the huge object, and the lower 32 bits are used to store the region index
978     uint64_t snapshotData_;
979     uintptr_t localHeap_ {0};
980 
981     friend class Snapshot;
982     friend class SnapshotProcessor;
983 };
984 }  // namespace ecmascript
985 }  // namespace panda
986 #endif  // ECMASCRIPT_MEM_REGION_H
987