Skip to content

Commit e95e7b8

Browse files
rmacnak-googleCommit Queue
authored andcommitted
[vm, gc] Mark through new-space.
- Initial and final marking no longer visit all of new-space, reducing the STW pause for major GC. - A scavenge during concurrent marking must forward / filter objects in the marking worklist that are moved / collected, increasing the STW pause for minor GC. - Unreachable intergenerational cycles and weak references are collected in the next mark-sweep instead of first requiring enough scavenges to promote the whole cycle or weak target into old-space. - Artificial minor GCs are no longer needed to avoid memory leaks from back-to-back major GCs. - reachabilityBarrier is now just a count of major GCs. TEST=ci Change-Id: I8c2c64b120766571b62d3bd8dab37ae81c2dca98 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/319583 Commit-Queue: Ryan Macnak <[email protected]> Reviewed-by: Siva Annamalai <[email protected]>
1 parent 0140ecd commit e95e7b8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+875
-506
lines changed

runtime/docs/gc.md

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -57,17 +57,9 @@ FLAG_scavenger_tasks (default 2) workers are started on separate threads. Each w
5757

5858
All objects have a bit in their header called the mark bit. At the start of a collection cycle, all objects have this bit clear.
5959

60-
During the marking phase, the collector visits each of the root pointers. If the target object is an old-space object and its mark bit is clear, the mark bit is set and the target added to the marking stack (grey set). The collector then removes and visits objects in the marking stack, marking more old-space objects and adding them to the marking stack, until the marking stack is empty. At this point, all reachable objects have their mark bits set and all unreachable objects have their mark bits clear.
60+
During the marking phase, the collector visits each of the root pointers. If the target object has its mark bit clear, the mark bit is set and the target added to the marking stack (grey set). The collector then removes and visits objects in the marking stack, marking more objects and adding them to the marking stack, until the marking stack is empty. At this point, all reachable objects have their mark bits set and all unreachable objects have their mark bits clear.
6161

62-
During the sweeping phase, the collector visits each old-space object. If the mark bit is clear, the object's memory is added to a [free list](https://github.com/dart-lang/sdk/blob/main/runtime/vm/heap/freelist.h) to be used for future allocations. Otherwise the object's mark bit is cleared. If every object on some page is unreachable, the page is released to the OS.
63-
64-
### New-Space as Roots
65-
66-
We do not mark new-space objects, and pointers to new-space objects are ignored; instead all objects in new-space are treated as part of the root set.
67-
68-
This has the advantage of making collections of the two spaces more independent. In particular, the concurrent marker never needs to dereference any memory in new-space, avoiding several data race issues, and avoiding the need to pause or otherwise synchronize with the concurrent marker when starting a scavenge.
69-
70-
It has the disadvantage that no single collection will collect all garbage. An unreachable old-space object that is referenced by an unreachable new-space object will not be collected until a scavenge first collects the new-space object, and unreachable objects that have a generation-crossing cycle will not be collected until the whole subgraph is promoted into old-space. The growth policy must be careful to ensure it doesn't perform old-space collections without interleaving new-space collections, such as when the program performs mostly large allocation that go directly to old-space, or old-space can accumulate such floating garbage and grow without bound.
62+
During the sweeping phase, the collector visits each object. If the mark bit is clear, the object's memory is added to a [free list](https://github.com/dart-lang/sdk/blob/main/runtime/vm/heap/freelist.h) to be used for future allocations. Otherwise the object's mark bit is cleared. If every object on some page is unreachable, the page is released to the OS.
7163

7264
## Mark-Compact
7365

@@ -103,17 +95,17 @@ But we combine the generational and incremental checks with a shift-and-mask.
10395
```c++
10496
enum HeaderBits {
10597
...
106-
kOldAndNotMarkedBit, // Incremental barrier target.
98+
kNotMarkedBit, // Incremental barrier target.
10799
kNewBit, // Generational barrier target.
108-
kOldBit, // Incremental barrier source.
100+
kAlwaysSetBit, // Incremental barrier source.
109101
kOldAndNotRememberedBit, // Generational barrier source.
110102
...
111103
};
112104
113105
static constexpr intptr_t kGenerationalBarrierMask = 1 << kNewBit;
114-
static constexpr intptr_t kIncrementalBarrierMask = 1 << kOldAndNotMarkedBit;
106+
static constexpr intptr_t kIncrementalBarrierMask = 1 << kNotMarkedBit;
115107
static constexpr intptr_t kBarrierOverlapShift = 2;
116-
COMPILE_ASSERT(kOldAndNotMarkedBit + kBarrierOverlapShift == kOldBit);
108+
COMPILE_ASSERT(kNotMarkedBit + kBarrierOverlapShift == kAlwaysSetBit);
117109
COMPILE_ASSERT(kNewBit + kBarrierOverlapShift == kOldAndNotRememberedBit);
118110
119111
StorePointer(ObjectPtr source, ObjectPtr* slot, ObjectPtr target) {

runtime/platform/atomic.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,27 @@ class AcqRelAtomic {
146146
std::atomic<T> value_;
147147
};
148148

149+
template <typename T>
150+
static inline T LoadRelaxed(const T* ptr) {
151+
static_assert(sizeof(std::atomic<T>) == sizeof(T));
152+
return reinterpret_cast<const std::atomic<T>*>(ptr)->load(
153+
std::memory_order_relaxed);
154+
}
155+
156+
template <typename T>
157+
static inline T LoadAcquire(const T* ptr) {
158+
static_assert(sizeof(std::atomic<T>) == sizeof(T));
159+
return reinterpret_cast<const std::atomic<T>*>(ptr)->load(
160+
std::memory_order_acquire);
161+
}
162+
163+
template <typename T>
164+
static inline void StoreRelease(T* ptr, T value) {
165+
static_assert(sizeof(std::atomic<T>) == sizeof(T));
166+
reinterpret_cast<std::atomic<T>*>(ptr)->store(value,
167+
std::memory_order_release);
168+
}
169+
149170
} // namespace dart
150171

151172
#endif // RUNTIME_PLATFORM_ATOMIC_H_

runtime/vm/app_snapshot.cc

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -875,8 +875,8 @@ void Deserializer::InitializeHeader(ObjectPtr raw,
875875
tags = UntaggedObject::ClassIdTag::update(class_id, tags);
876876
tags = UntaggedObject::SizeTag::update(size, tags);
877877
tags = UntaggedObject::CanonicalBit::update(is_canonical, tags);
878-
tags = UntaggedObject::OldBit::update(true, tags);
879-
tags = UntaggedObject::OldAndNotMarkedBit::update(true, tags);
878+
tags = UntaggedObject::AlwaysSetBit::update(true, tags);
879+
tags = UntaggedObject::NotMarkedBit::update(true, tags);
880880
tags = UntaggedObject::OldAndNotRememberedBit::update(true, tags);
881881
tags = UntaggedObject::NewBit::update(false, tags);
882882
raw->untag()->tags_ = tags;

runtime/vm/compiler/runtime_api.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,8 @@ uword MakeTagWordForNewSpaceObject(classid_t cid, uword instance_size) {
360360
TranslateOffsetInWordsToHost(instance_size)) |
361361
dart::UntaggedObject::ClassIdTag::encode(cid) |
362362
dart::UntaggedObject::NewBit::encode(true) |
363+
dart::UntaggedObject::AlwaysSetBit::encode(true) |
364+
dart::UntaggedObject::NotMarkedBit::encode(true) |
363365
dart::UntaggedObject::ImmutableBit::encode(
364366
ShouldHaveImmutabilityBitSet(cid));
365367
}
@@ -378,8 +380,7 @@ const word UntaggedObject::kNewBit = dart::UntaggedObject::kNewBit;
378380
const word UntaggedObject::kOldAndNotRememberedBit =
379381
dart::UntaggedObject::kOldAndNotRememberedBit;
380382

381-
const word UntaggedObject::kOldAndNotMarkedBit =
382-
dart::UntaggedObject::kOldAndNotMarkedBit;
383+
const word UntaggedObject::kNotMarkedBit = dart::UntaggedObject::kNotMarkedBit;
383384

384385
const word UntaggedObject::kImmutableBit = dart::UntaggedObject::kImmutableBit;
385386

runtime/vm/compiler/runtime_api.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ class UntaggedObject : public AllStatic {
418418
static const word kCanonicalBit;
419419
static const word kNewBit;
420420
static const word kOldAndNotRememberedBit;
421-
static const word kOldAndNotMarkedBit;
421+
static const word kNotMarkedBit;
422422
static const word kImmutableBit;
423423
static const word kSizeTagPos;
424424
static const word kSizeTagSize;
@@ -1493,6 +1493,8 @@ class Page : public AllStatic {
14931493
static const word kBytesPerCardLog2;
14941494

14951495
static word card_table_offset();
1496+
static word original_top_offset();
1497+
static word original_end_offset();
14961498
};
14971499

14981500
class Heap : public AllStatic {

0 commit comments

Comments
 (0)