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