• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2022 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/base/aligned_struct.h"
20 #include "ecmascript/base/asan_interface.h"
21 #include "ecmascript/js_tagged_value.h"
22 #include "ecmascript/mem/free_object_list.h"
23 #include "ecmascript/mem/gc_bitset.h"
24 #include "ecmascript/mem/remembered_set.h"
25 #include "ecmascript/mem/mem_common.h"
26 #include "ecmascript/platform/map.h"
27 
28 #include "ecmascript/platform/mutex.h"
29 
30 #include "securec.h"
31 
32 namespace panda {
33 namespace ecmascript {
34 class JSThread;
35 
36 enum RegionSpaceFlag {
37     UNINITIALIZED = 0,
38     // We should avoid using the lower 3 bits (bits 0 to 2).
39     // If ZAP_MEM is enabled, the value of the lower 3 bits conflicts with the INVALID_VALUE.
40 
41     // Bits 3 to 7 are reserved to denote the space where the region is located.
42     IN_YOUNG_SPACE = 0x08,
43     IN_SNAPSHOT_SPACE = 0x09,
44     IN_HUGE_OBJECT_SPACE = 0x0A,
45     IN_OLD_SPACE = 0x0B,
46     IN_NON_MOVABLE_SPACE = 0x0C,
47     IN_MACHINE_CODE_SPACE = 0x0D,
48     IN_READ_ONLY_SPACE = 0x0E,
49     IN_APPSPAWN_SPACE = 0X0F,
50     IN_HUGE_MACHINE_CODE_SPACE = 0x10,
51 
52     VALID_SPACE_MASK = 0xFF,
53 };
54 
55 enum RegionGCFlags {
56     // We should avoid using the lower 3 bits (bits 0 to 2).
57     // If ZAP_MEM is enabled, the value of the lower 3 bits conflicts with the INVALID_VALUE.
58 
59     // Below flags are used for GC, and each flag has a dedicated bit starting from the 3rd bit.
60     NEVER_EVACUATE = 1 << 3,
61     HAS_AGE_MARK = 1 << 4,
62     BELOW_AGE_MARK = 1 << 5,
63     IN_COLLECT_SET = 1 << 6,
64     IN_NEW_TO_NEW_SET = 1 << 7,
65     // Bits 8 to 10 (the lower 3 bits for the next byte) are also excluded for the sake of
66     // INVALID_VALUE in ZAP_MEM.
67     HAS_BEEN_SWEPT = 1 << 11,
68     NEED_RELOCATE = 1 << 12,
69     // ONLY used for heap verification.
70     IN_INACTIVE_SEMI_SPACE = 1 << 13,
71 };
72 
ToSpaceTypeName(uint8_t space)73 static inline std::string ToSpaceTypeName(uint8_t space)
74 {
75     switch (space) {
76         case RegionSpaceFlag::IN_YOUNG_SPACE:
77             return "young space";
78         case RegionSpaceFlag::IN_SNAPSHOT_SPACE:
79             return "snapshot space";
80         case RegionSpaceFlag::IN_HUGE_OBJECT_SPACE:
81             return "huge object space";
82         case RegionSpaceFlag::IN_OLD_SPACE:
83             return "old space";
84         case RegionSpaceFlag::IN_NON_MOVABLE_SPACE:
85             return "non movable space";
86         case RegionSpaceFlag::IN_MACHINE_CODE_SPACE:
87             return "machine code space";
88         case RegionSpaceFlag::IN_READ_ONLY_SPACE:
89             return "read only space";
90         case RegionSpaceFlag::IN_APPSPAWN_SPACE:
91             return "appspawn space";
92         case RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE:
93             return "huge machine code space";
94         default:
95             return "invalid space";
96     }
97 }
98 
99 // |---------------------------------------------------------------------------------------|
100 // |                                   Region (256 kb)                                     |
101 // |---------------------------------|--------------------------------|--------------------|
102 // |     Head (sizeof(Region))       |         Mark bitset (4kb)      |      Data          |
103 // |---------------------------------|--------------------------------|--------------------|
104 
105 class Region {
106 public:
Region(JSThread * thread,uintptr_t allocateBase,uintptr_t begin,uintptr_t end,RegionSpaceFlag spaceType)107     Region(JSThread *thread, uintptr_t allocateBase, uintptr_t begin, uintptr_t end, RegionSpaceFlag spaceType)
108         : packedData_(begin, end, spaceType),
109           thread_(thread),
110           allocateBase_(allocateBase),
111           end_(end),
112           highWaterMark_(end),
113           aliveObject_(0),
114           wasted_(0),
115           snapshotData_(0)
116     {
117         lock_ = new Mutex();
118     }
119 
120     ~Region() = default;
121 
122     NO_COPY_SEMANTIC(Region);
123     NO_MOVE_SEMANTIC(Region);
124 
LinkNext(Region * next)125     void LinkNext(Region *next)
126     {
127         next_ = next;
128     }
129 
GetNext()130     Region *GetNext() const
131     {
132         return next_;
133     }
134 
LinkPrev(Region * prev)135     void LinkPrev(Region *prev)
136     {
137         prev_ = prev;
138     }
139 
GetPrev()140     Region *GetPrev() const
141     {
142         return prev_;
143     }
144 
GetBegin()145     uintptr_t GetBegin() const
146     {
147         return packedData_.begin_;
148     }
149 
GetEnd()150     uintptr_t GetEnd() const
151     {
152         return end_;
153     }
154 
GetHighWaterMark()155     uintptr_t GetHighWaterMark() const
156     {
157         return highWaterMark_;
158     }
159 
GetCapacity()160     size_t GetCapacity() const
161     {
162         return end_ - allocateBase_;
163     }
164 
GetSize()165     size_t GetSize() const
166     {
167         return end_ - packedData_.begin_;
168     }
169 
IsGCFlagSet(RegionGCFlags flag)170     bool IsGCFlagSet(RegionGCFlags flag) const
171     {
172         return (packedData_.flags_.gcFlags_ & flag) == flag;
173     }
174 
SetGCFlag(RegionGCFlags flag)175     void SetGCFlag(RegionGCFlags flag)
176     {
177         packedData_.flags_.gcFlags_ |= flag;
178     }
179 
ClearGCFlag(RegionGCFlags flag)180     void ClearGCFlag(RegionGCFlags flag)
181     {
182         // NOLINTNEXTLINE(hicpp-signed-bitwise)
183         packedData_.flags_.gcFlags_ &= ~flag;
184     }
185 
GetSpaceTypeName()186     std::string GetSpaceTypeName()
187     {
188         return ToSpaceTypeName(packedData_.flags_.spaceFlag_);
189     }
190 
191     // Mark bitset
192     GCBitset *GetMarkGCBitset() const;
193     bool AtomicMark(void *address);
194     void ClearMark(void *address);
195     bool Test(void *addr) const;
196     // ONLY used for heap verification.
197     bool TestOldToNew(uintptr_t addr);
198     template <typename Visitor>
199     void IterateAllMarkedBits(Visitor visitor) const;
200     void ClearMarkGCBitset();
201     // Cross region remembered set
202     void InsertCrossRegionRSet(uintptr_t addr);
203     void AtomicInsertCrossRegionRSet(uintptr_t addr);
204     template <typename Visitor>
205     void IterateAllCrossRegionBits(Visitor visitor) const;
206     void ClearCrossRegionRSet();
207     void ClearCrossRegionRSetInRange(uintptr_t start, uintptr_t end);
208     void AtomicClearCrossRegionRSetInRange(uintptr_t start, uintptr_t end);
209     void DeleteCrossRegionRSet();
210     // Old to new remembered set
211     void InsertOldToNewRSet(uintptr_t addr);
212     void ClearOldToNewRSet(uintptr_t addr);
213     template <typename Visitor>
214     void IterateAllOldToNewBits(Visitor visitor);
215     void ClearOldToNewRSet();
216     void ClearOldToNewRSetInRange(uintptr_t start, uintptr_t end);
217     void DeleteOldToNewRSet();
218 
219     void AtomicClearSweepingRSetInRange(uintptr_t start, uintptr_t end);
220     void ClearSweepingRSetInRange(uintptr_t start, uintptr_t end);
221     void DeleteSweepingRSet();
222     template <typename Visitor>
223     void AtomicIterateAllSweepingRSetBits(Visitor visitor);
224     template <typename Visitor>
225     void IterateAllSweepingRSetBits(Visitor visitor);
226 
ObjectAddressToRange(TaggedObject * obj)227     static Region *ObjectAddressToRange(TaggedObject *obj)
228     {
229         return reinterpret_cast<Region *>(ToUintPtr(obj) & ~DEFAULT_REGION_MASK);
230     }
231 
ObjectAddressToRange(uintptr_t objAddress)232     static Region *ObjectAddressToRange(uintptr_t objAddress)
233     {
234         return reinterpret_cast<Region *>(objAddress & ~DEFAULT_REGION_MASK);
235     }
236 
GetRegionAvailableSize()237     static size_t GetRegionAvailableSize()
238     {
239         size_t regionHeaderSize = AlignUp(sizeof(Region), static_cast<size_t>(MemAlignment::MEM_ALIGN_REGION));
240         size_t bitsetSize = GCBitset::SizeOfGCBitset(DEFAULT_REGION_SIZE - regionHeaderSize);
241         return DEFAULT_REGION_SIZE - regionHeaderSize - bitsetSize;
242     }
243 
ClearMembers()244     void ClearMembers()
245     {
246         if (lock_ != nullptr) {
247             delete lock_;
248             lock_ = nullptr;
249         }
250     }
251 
Invalidate()252     void Invalidate()
253     {
254         ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<void *>(GetBegin()), GetSize());
255         packedData_.flags_.spaceFlag_ = RegionSpaceFlag::UNINITIALIZED;
256     }
257 
InYoungSpace()258     bool InYoungSpace() const
259     {
260         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_YOUNG_SPACE;
261     }
262 
InOldSpace()263     bool InOldSpace() const
264     {
265         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_OLD_SPACE;
266     }
267 
InYoungOrOldSpace()268     bool InYoungOrOldSpace() const
269     {
270         return InYoungSpace() || InOldSpace();
271     }
272 
InHugeObjectSpace()273     bool InHugeObjectSpace() const
274     {
275         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_HUGE_OBJECT_SPACE;
276     }
277 
InMachineCodeSpace()278     bool InMachineCodeSpace() const
279     {
280         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_MACHINE_CODE_SPACE;
281     }
282 
InHugeMachineCodeSpace()283     bool InHugeMachineCodeSpace() const
284     {
285         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE;
286     }
287 
InNonMovableSpace()288     bool InNonMovableSpace() const
289     {
290         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_NON_MOVABLE_SPACE;
291     }
292 
InSnapshotSpace()293     bool InSnapshotSpace() const
294     {
295         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_SNAPSHOT_SPACE;
296     }
297 
InReadOnlySpace()298     bool InReadOnlySpace() const
299     {
300         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_READ_ONLY_SPACE;
301     }
302 
InAppSpawnSpace()303     bool InAppSpawnSpace() const
304     {
305         return packedData_.flags_.spaceFlag_ == RegionSpaceFlag::IN_APPSPAWN_SPACE;
306     }
307 
InHeapSpace()308     bool InHeapSpace() const
309     {
310         uint8_t space = packedData_.flags_.spaceFlag_;
311         return (space == RegionSpaceFlag::IN_YOUNG_SPACE ||
312                 space == RegionSpaceFlag::IN_OLD_SPACE ||
313                 space == RegionSpaceFlag::IN_HUGE_OBJECT_SPACE ||
314                 space == RegionSpaceFlag::IN_MACHINE_CODE_SPACE ||
315                 space == RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE ||
316                 space == RegionSpaceFlag::IN_NON_MOVABLE_SPACE ||
317                 space == RegionSpaceFlag::IN_SNAPSHOT_SPACE ||
318                 space == RegionSpaceFlag::IN_READ_ONLY_SPACE ||
319                 space == RegionSpaceFlag::IN_APPSPAWN_SPACE);
320     }
321 
InCollectSet()322     bool InCollectSet() const
323     {
324         return IsGCFlagSet(RegionGCFlags::IN_COLLECT_SET);
325     }
326 
InYoungSpaceOrCSet()327     bool InYoungSpaceOrCSet() const
328     {
329         return InYoungSpace() || InCollectSet();
330     }
331 
InNewToNewSet()332     bool InNewToNewSet() const
333     {
334         return IsGCFlagSet(RegionGCFlags::IN_NEW_TO_NEW_SET);
335     }
336 
HasAgeMark()337     bool HasAgeMark() const
338     {
339         return IsGCFlagSet(RegionGCFlags::HAS_AGE_MARK);
340     }
341 
BelowAgeMark()342     bool BelowAgeMark() const
343     {
344         return IsGCFlagSet(RegionGCFlags::BELOW_AGE_MARK);
345     }
346 
NeedRelocate()347     bool NeedRelocate() const
348     {
349         return IsGCFlagSet(RegionGCFlags::NEED_RELOCATE);
350     }
351 
352     // ONLY used for heap verification.
InInactiveSemiSpace()353     bool InInactiveSemiSpace() const
354     {
355         return IsGCFlagSet(RegionGCFlags::IN_INACTIVE_SEMI_SPACE);
356     }
357 
358     // ONLY used for heap verification.
InActiveSemiSpace()359     bool InActiveSemiSpace() const
360     {
361         return InYoungSpace() && !InInactiveSemiSpace();
362     }
363 
364     // ONLY used for heap verification.
SetInactiveSemiSpace()365     void SetInactiveSemiSpace()
366     {
367         SetGCFlag(RegionGCFlags::IN_INACTIVE_SEMI_SPACE);
368     }
369 
370     // ONLY used for heap verification.
ResetInactiveSemiSpace()371     void ResetInactiveSemiSpace()
372     {
373         ClearGCFlag(RegionGCFlags::IN_INACTIVE_SEMI_SPACE);
374     }
375 
SetSwept()376     void SetSwept()
377     {
378         SetGCFlag(RegionGCFlags::HAS_BEEN_SWEPT);
379     }
380 
ResetSwept()381     void ResetSwept()
382     {
383         ClearGCFlag(RegionGCFlags::HAS_BEEN_SWEPT);
384     }
385 
InRange(uintptr_t address)386     bool InRange(uintptr_t address) const
387     {
388         return address >= packedData_.begin_ && address <= end_;
389     }
390 
GetAllocateBase()391     uintptr_t GetAllocateBase() const
392     {
393         return allocateBase_;
394     }
395 
396     size_t GetAllocatedBytes(uintptr_t top = 0)
397     {
398         ASSERT(top == 0 || InRange(top));
399         return (top == 0) ? (highWaterMark_ - packedData_.begin_) : (top - packedData_.begin_);
400     }
401 
SetHighWaterMark(uintptr_t mark)402     void SetHighWaterMark(uintptr_t mark)
403     {
404         ASSERT(InRange(mark));
405         highWaterMark_ = mark;
406     }
407 
SetReadOnlyAndMarked()408     void SetReadOnlyAndMarked()
409     {
410         packedData_.markGCBitset_->SetAllBits(packedData_.bitsetSize_);
411         PageProtect(reinterpret_cast<void *>(allocateBase_), GetCapacity(), PAGE_PROT_READ);
412     }
413 
ClearReadOnly()414     void ClearReadOnly()
415     {
416         PageProtect(reinterpret_cast<void *>(allocateBase_), GetCapacity(), PAGE_PROT_READWRITE);
417     }
418 
InitializeFreeObjectSets()419     void InitializeFreeObjectSets()
420     {
421         freeObjectSets_ = Span<FreeObjectSet *>(new FreeObjectSet *[FreeObjectList::NumberOfSets()](),
422             FreeObjectList::NumberOfSets());
423     }
424 
DestroyFreeObjectSets()425     void DestroyFreeObjectSets()
426     {
427         for (auto set : freeObjectSets_) {
428             delete set;
429         }
430         delete[] freeObjectSets_.data();
431     }
432 
GetFreeObjectSet(SetType type)433     FreeObjectSet *GetFreeObjectSet(SetType type)
434     {
435         // Thread safe
436         if (freeObjectSets_[type] == nullptr) {
437             freeObjectSets_[type] = new FreeObjectSet(type);
438         }
439         return freeObjectSets_[type];
440     }
441 
442     template<class Callback>
EnumerateFreeObjectSets(Callback cb)443     void EnumerateFreeObjectSets(Callback cb)
444     {
445         for (auto set : freeObjectSets_) {
446             cb(set);
447         }
448     }
449 
450     template<class Callback>
REnumerateFreeObjectSets(Callback cb)451     void REnumerateFreeObjectSets(Callback cb)
452     {
453         auto last = freeObjectSets_.crbegin();
454         auto first = freeObjectSets_.crend();
455         for (; last != first; last++) {
456             if (!cb(*last)) {
457                 break;
458             }
459         }
460     }
461 
IncreaseAliveObjectSafe(size_t size)462     void IncreaseAliveObjectSafe(size_t size)
463     {
464         ASSERT(aliveObject_ + size <= GetSize());
465         aliveObject_ += size;
466     }
467 
IncreaseAliveObject(size_t size)468     void IncreaseAliveObject(size_t size)
469     {
470         ASSERT(aliveObject_ + size <= GetSize());
471         aliveObject_.fetch_add(size, std::memory_order_relaxed);
472     }
473 
SetRegionAliveSize()474     void SetRegionAliveSize()
475     {
476         gcAliveSize_ = aliveObject_;
477     }
478 
ResetAliveObject()479     void ResetAliveObject()
480     {
481         aliveObject_ = 0;
482     }
483 
AliveObject()484     size_t AliveObject() const
485     {
486         return aliveObject_.load(std::memory_order_relaxed);
487     }
488 
GetGCAliveSize()489     size_t GetGCAliveSize() const
490     {
491         return gcAliveSize_;
492     }
493 
MostObjectAlive()494     bool MostObjectAlive() const
495     {
496         return aliveObject_ > MOST_OBJECT_ALIVE_THRESHOLD_PERCENT * GetSize();
497     }
498 
BelowCompressThreasholdAlive()499     bool BelowCompressThreasholdAlive() const
500     {
501         return gcAliveSize_ < COMPRESS_THREASHOLD_PERCENT * GetSize();
502     }
503 
ResetWasted()504     void ResetWasted()
505     {
506         wasted_ = 0;
507     }
508 
IncreaseWasted(uint64_t size)509     void IncreaseWasted(uint64_t size)
510     {
511         wasted_ += size;
512     }
513 
GetWastedSize()514     uint64_t GetWastedSize()
515     {
516         return wasted_;
517     }
518 
GetSnapshotData()519     uint64_t GetSnapshotData()
520     {
521         return snapshotData_;
522     }
523 
SetSnapshotData(uint64_t value)524     void SetSnapshotData(uint64_t value)
525     {
526         snapshotData_ = value;
527     }
528 
SwapRSetForConcurrentSweeping()529     void SwapRSetForConcurrentSweeping()
530     {
531         sweepingRSet_ = packedData_.oldToNewSet_;
532         packedData_.oldToNewSet_ = nullptr;
533     }
534 
535     // should call in js-thread
536     void MergeRSetForConcurrentSweeping();
537 
538     struct alignas(JSTaggedValue::TaggedTypeSize()) PackedPtr : public base::AlignedPointer {
539         uint8_t spaceFlag_;
540         uint16_t  gcFlags_;
541     };
542 
543     struct PackedData : public base::AlignedStruct<JSTaggedValue::TaggedTypeSize(),
544                                                  base::AlignedPointer,
545                                                  base::AlignedPointer,
546                                                  base::AlignedPointer,
547                                                  base::AlignedPointer,
548                                                  base::AlignedSize> {
549         enum class Index : size_t {
550             FlagIndex = 0,
551             MarkGCBitSetIndex,
552             OldToNewSetIndex,
553             BeginIndex,
554             BitSetSizeIndex,
555             NumOfMembers
556         };
557 
558         static_assert(static_cast<size_t>(Index::NumOfMembers) == NumOfTypes);
559 
PackedDataPackedData560         inline PackedData(uintptr_t begin, uintptr_t end, RegionSpaceFlag spaceType)
561         {
562             flags_.spaceFlag_ = spaceType;
563             flags_.gcFlags_ = 0;
564             bitsetSize_ = (spaceType == RegionSpaceFlag::IN_HUGE_OBJECT_SPACE ||
565                            spaceType == RegionSpaceFlag::IN_HUGE_MACHINE_CODE_SPACE) ?
566                 GCBitset::BYTE_PER_WORD : GCBitset::SizeOfGCBitset(end - begin);
567             markGCBitset_ = new (ToVoidPtr(begin)) GCBitset();
568             markGCBitset_->Clear(bitsetSize_);
569             begin_ = AlignUp(begin + bitsetSize_, static_cast<size_t>(MemAlignment::MEM_ALIGN_OBJECT));
570             // The object region marked with poison until it is allocated if is_asan is true
571             ASAN_POISON_MEMORY_REGION(reinterpret_cast<void *>(begin_), (end - begin_));
572         }
573 
GetFlagOffsetPackedData574         static size_t GetFlagOffset(bool isArch32)
575         {
576             return GetOffset<static_cast<size_t>(Index::FlagIndex)>(isArch32);
577         }
578 
GetGCBitsetOffsetPackedData579         static size_t GetGCBitsetOffset(bool isArch32)
580         {
581             return GetOffset<static_cast<size_t>(Index::MarkGCBitSetIndex)>(isArch32);
582         }
583 
GetOldToNewSetOffsetPackedData584         static size_t GetOldToNewSetOffset(bool isArch32)
585         {
586             return GetOffset<static_cast<size_t>(Index::OldToNewSetIndex)>(isArch32);
587         }
588 
GetBeginOffsetPackedData589         static size_t GetBeginOffset(bool isArch32)
590         {
591             return GetOffset<static_cast<size_t>(Index::BeginIndex)>(isArch32);
592         }
593 
594         alignas(EAS) PackedPtr flags_;
595         alignas(EAS) GCBitset *markGCBitset_ {nullptr};
596         alignas(EAS) RememberedSet *oldToNewSet_ {nullptr};
597         alignas(EAS) uintptr_t begin_ {0};
598         alignas(EAS) size_t bitsetSize_ {0};
599     };
600     STATIC_ASSERT_EQ_ARCH(sizeof(PackedData), PackedData::SizeArch32, PackedData::SizeArch64);
601 
602     static constexpr double MOST_OBJECT_ALIVE_THRESHOLD_PERCENT = 0.8;
603     static constexpr double AVERAGE_REGION_EVACUATE_SIZE = MOST_OBJECT_ALIVE_THRESHOLD_PERCENT *
604                                                            DEFAULT_REGION_SIZE / 2;  // 2 means half
605 private:
606     static constexpr double COMPRESS_THREASHOLD_PERCENT = 0.1;
607 
608     RememberedSet *CreateRememberedSet();
609     RememberedSet *GetOrCreateCrossRegionRememberedSet();
610     RememberedSet *GetOrCreateOldToNewRememberedSet();
611 
612     PackedData packedData_;
613     /*
614      * The thread instance here is used by the GC barriers to get marking related information
615      * and perform marking related operations. The barriers will indirectly access such information
616      * via. the objects' associated regions.
617      * fixme: Figure out a more elegant solution to bridging the barrier
618      * and the information / operations it depends on. Then we can get rid of this from the region,
619      * and consequently, the region allocator, the spaces using the region allocator, etc.
620      */
621     JSThread *thread_;
622 
623     uintptr_t allocateBase_;
624     uintptr_t end_;
625     uintptr_t highWaterMark_;
626     std::atomic_size_t aliveObject_ {0};
627     size_t gcAliveSize_ {0};
628     Region *next_ {nullptr};
629     Region *prev_ {nullptr};
630 
631     RememberedSet *crossRegionSet_ {nullptr};
632     RememberedSet *sweepingRSet_ {nullptr};
633     Span<FreeObjectSet *> freeObjectSets_;
634     Mutex *lock_ {nullptr};
635     uint64_t wasted_;
636     // snapshotdata_ is used to encode the region for snapshot. Its upper 32 bits are used to store the size of
637     // the huge object, and the lower 32 bits are used to store the region index
638     uint64_t snapshotData_;
639 
640     friend class Snapshot;
641     friend class SnapshotProcessor;
642 };
643 }  // namespace ecmascript
644 }  // namespace panda
645 #endif  // ECMASCRIPT_MEM_REGION_H
646