Skip to content

Commit 07091b8

Browse files
committed
Composition instead of inheritance for ChunkedStack.
Also, rename TraceStack to TraversalWorklist because the fact that we're using a stack is an implementation detail.
1 parent 1c6e202 commit 07091b8

File tree

3 files changed

+67
-60
lines changed

3 files changed

+67
-60
lines changed

src/gc/collector.cpp

Lines changed: 60 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -125,16 +125,14 @@ class ChunkedStack {
125125
}
126126
}
127127

128-
inline void _push(void* p) {
129-
*cur++ = p;
130-
if (cur == end) {
131-
chunks.push_back(start);
132-
get_chunk();
133-
}
134-
}
135-
136128
public:
137129
ChunkedStack() { get_chunk(); }
130+
~ChunkedStack() {
131+
RELEASE_ASSERT(end - cur == CHUNK_SIZE, "destroying non-empty ChunkedStack");
132+
// We always have a block available in case we want to push items onto the TraversalWorklist,
133+
// but that chunk needs to be released after use to avoid a memory leak.
134+
release_chunk(start);
135+
}
138136

139137
void* pop() {
140138
if (cur > start) {
@@ -145,41 +143,50 @@ class ChunkedStack {
145143

146144
return previous_pop;
147145
}
146+
147+
void push(void* p) {
148+
*cur++ = p;
149+
if (cur == end) {
150+
chunks.push_back(start);
151+
get_chunk();
152+
}
153+
}
148154
};
149155
std::vector<void**> ChunkedStack::free_chunks;
150156

151-
enum TraceStackType {
157+
enum TraversalType {
152158
MarkPhase,
153159
FinalizationOrderingFindReachable,
154160
FinalizationOrderingRemoveTemporaries,
155161
MapReferencesPhase,
156162
};
157163

158-
class TraceStack : public ChunkedStack {
159-
TraceStackType visit_type;
164+
class Worklist {
165+
protected:
166+
ChunkedStack stack;
167+
168+
public:
169+
void* next() { return stack.pop(); }
170+
};
171+
172+
class TraversalWorklist : public Worklist {
173+
TraversalType visit_type;
160174

161175
public:
162-
TraceStack(TraceStackType type) : ChunkedStack(), visit_type(type) {}
163-
TraceStack(TraceStackType type, const std::unordered_set<void*>& roots) : TraceStack(type) {
176+
TraversalWorklist(TraversalType type) : visit_type(type) {}
177+
TraversalWorklist(TraversalType type, const std::unordered_set<void*>& roots) : TraversalWorklist(type) {
164178
for (void* p : roots) {
165179
ASSERT(!isMarked(GCAllocation::fromUserData(p)), "");
166-
push(p);
180+
addWork(p);
167181
}
168182
}
169-
~TraceStack() {
170-
RELEASE_ASSERT(end - cur == CHUNK_SIZE, "destroying non-empty TraceStack");
171183

172-
// We always have a block available in case we want to push items onto the TraceStack,
173-
// but that chunk needs to be released after use to avoid a memory leak.
174-
release_chunk(start);
175-
}
176-
177-
void push(void* p) {
184+
void addWork(void* p) {
178185
GC_TRACE_LOG("Pushing %p\n", p);
179186
GCAllocation* al = GCAllocation::fromUserData(p);
180187

181188
switch (visit_type) {
182-
case TraceStackType::MarkPhase:
189+
case TraversalType::MarkPhase:
183190
// Use this to print the directed edges of the GC graph traversal.
184191
// i.e. print every a -> b where a is a pointer and b is something a references
185192
#if 0
@@ -208,7 +215,7 @@ class TraceStack : public ChunkedStack {
208215
break;
209216
// See PyPy's finalization ordering algorithm:
210217
// http://pypy.readthedocs.org/en/latest/discussion/finalizer-order.html
211-
case TraceStackType::FinalizationOrderingFindReachable:
218+
case TraversalType::FinalizationOrderingFindReachable:
212219
if (orderingState(al) == FinalizationState::UNREACHABLE) {
213220
setOrderingState(al, FinalizationState::TEMPORARY);
214221
} else if (orderingState(al) == FinalizationState::REACHABLE_FROM_FINALIZER) {
@@ -217,7 +224,7 @@ class TraceStack : public ChunkedStack {
217224
return;
218225
}
219226
break;
220-
case TraceStackType::FinalizationOrderingRemoveTemporaries:
227+
case TraversalType::FinalizationOrderingRemoveTemporaries:
221228
if (orderingState(al) == FinalizationState::TEMPORARY) {
222229
setOrderingState(al, FinalizationState::REACHABLE_FROM_FINALIZER);
223230
} else {
@@ -228,22 +235,22 @@ class TraceStack : public ChunkedStack {
228235
assert(false);
229236
}
230237

231-
_push(p);
238+
stack.push(p);
232239
}
233240
};
234241

235-
class ReferenceMapStack : public ChunkedStack {
242+
class ReferenceMapWorklist : public Worklist {
236243
ReferenceMap* refmap;
237244

238245
public:
239-
ReferenceMapStack(ReferenceMap* refmap) : ChunkedStack(), refmap(refmap) {}
240-
ReferenceMapStack(ReferenceMap* refmap, const std::unordered_set<void*>& roots) : ChunkedStack(), refmap(refmap) {
246+
ReferenceMapWorklist(ReferenceMap* refmap) : refmap(refmap) {}
247+
ReferenceMapWorklist(ReferenceMap* refmap, const std::unordered_set<void*>& roots) : refmap(refmap) {
241248
for (void* p : roots) {
242-
push(GCAllocation::fromUserData(p), NULL);
249+
addWork(GCAllocation::fromUserData(p), NULL);
243250
}
244251
}
245252

246-
void push(GCAllocation* al, GCAllocation* source) {
253+
void addWork(GCAllocation* al, GCAllocation* source) {
247254
assert(refmap);
248255

249256
auto it = refmap->references.find(al);
@@ -270,7 +277,7 @@ class ReferenceMapStack : public ChunkedStack {
270277
}
271278
}
272279

273-
_push(al->user_data);
280+
stack.push(al->user_data);
274281
} else {
275282
if (source) {
276283
// We found that there exists a pointer from `source` to `al`
@@ -435,7 +442,7 @@ void GCVisitor::_visit(void** ptr_address) {
435442
}
436443

437444
ASSERT(global_heap.getAllocationFromInteriorPointer(p)->user_data == p, "%p", p);
438-
stack->push(p);
445+
worklist->addWork(p);
439446
}
440447

441448
void GCVisitor::_visitRange(void** start, void** end) {
@@ -454,7 +461,7 @@ void GCVisitor::_visitRange(void** start, void** end) {
454461
void GCVisitor::visitPotential(void* p) {
455462
GCAllocation* a = global_heap.getAllocationFromInteriorPointer(p);
456463
if (a) {
457-
stack->push(a->user_data);
464+
worklist->addWork(a->user_data);
458465
}
459466
}
460467

@@ -491,14 +498,14 @@ void GCVisitorPinning::_visit(void** ptr_address) {
491498

492499
GCAllocation* al = global_heap.getAllocationFromInteriorPointer(p);
493500
ASSERT(al->user_data == p, "%p", p);
494-
stack->push(al, source);
501+
worklist->addWork(al, source);
495502
}
496503

497504
void GCVisitorPinning::visitPotential(void* p) {
498505
GCAllocation* a = global_heap.getAllocationFromInteriorPointer(p);
499506
if (a) {
500-
stack->pin(a);
501-
stack->push(a, source);
507+
worklist->pin(a);
508+
worklist->addWork(a, source);
502509
}
503510
}
504511

@@ -538,11 +545,11 @@ static void finalizationOrderingFindReachable(Box* obj) {
538545
static StatCounter sc_us("us_gc_mark_finalizer_ordering_1");
539546
Timer _t("finalizationOrderingFindReachable", /*min_usec=*/10000);
540547

541-
TraceStack stack(TraceStackType::FinalizationOrderingFindReachable);
542-
GCVisitor visitor(&stack);
548+
TraversalWorklist worklist(TraversalType::FinalizationOrderingFindReachable);
549+
GCVisitor visitor(&worklist);
543550

544-
stack.push(obj);
545-
while (void* p = stack.pop()) {
551+
worklist.addWork(obj);
552+
while (void* p = worklist.next()) {
546553
sc_marked_objs.log();
547554

548555
visitByGCKind(p, visitor);
@@ -556,11 +563,11 @@ static void finalizationOrderingRemoveTemporaries(Box* obj) {
556563
static StatCounter sc_us("us_gc_mark_finalizer_ordering_2");
557564
Timer _t("finalizationOrderingRemoveTemporaries", /*min_usec=*/10000);
558565

559-
TraceStack stack(TraceStackType::FinalizationOrderingRemoveTemporaries);
560-
GCVisitor visitor(&stack);
566+
TraversalWorklist worklist(TraversalType::FinalizationOrderingRemoveTemporaries);
567+
GCVisitor visitor(&worklist);
561568

562-
stack.push(obj);
563-
while (void* p = stack.pop()) {
569+
worklist.addWork(obj);
570+
while (void* p = worklist.next()) {
564571
GCAllocation* al = GCAllocation::fromUserData(p);
565572
assert(orderingState(al) != FinalizationState::UNREACHABLE);
566573
visitByGCKind(p, visitor);
@@ -606,12 +613,12 @@ static void orderFinalizers() {
606613
sc_us.log(us);
607614
}
608615

609-
static void graphTraversalMarking(ChunkedStack& stack, GCVisitor& visitor) {
616+
static void graphTraversalMarking(Worklist& worklist, GCVisitor& visitor) {
610617
static StatCounter sc_us("us_gc_mark_phase_graph_traversal");
611618
static StatCounter sc_marked_objs("gc_marked_object_count");
612619
Timer _t("traversing", /*min_usec=*/10000);
613620

614-
while (void* p = stack.pop()) {
621+
while (void* p = worklist.next()) {
615622
sc_marked_objs.log();
616623

617624
GCAllocation* al = GCAllocation::fromUserData(p);
@@ -741,12 +748,12 @@ static void markPhase() {
741748
GC_TRACE_LOG("Starting collection %d\n", ncollections);
742749

743750
GC_TRACE_LOG("Looking at roots\n");
744-
TraceStack stack(TraceStackType::MarkPhase, roots);
745-
GCVisitor visitor(&stack);
751+
TraversalWorklist worklist(TraversalType::MarkPhase, roots);
752+
GCVisitor visitor(&worklist);
746753

747754
visitRoots(visitor);
748755

749-
graphTraversalMarking(stack, visitor);
756+
graphTraversalMarking(worklist, visitor);
750757

751758
// Objects with finalizers cannot be freed in any order. During the call to a finalizer
752759
// of an object, the finalizer expects the object's references to still point to valid
@@ -775,16 +782,16 @@ static void sweepPhase(std::vector<Box*>& weakly_referenced) {
775782
}
776783

777784
static void mapReferencesPhase(ReferenceMap& refmap) {
778-
ReferenceMapStack stack(&refmap, roots);
779-
GCVisitorPinning visitor(&stack);
785+
ReferenceMapWorklist worklist(&refmap, roots);
786+
GCVisitorPinning visitor(&worklist);
780787

781788
visitRoots(visitor);
782789

783790
for (auto obj : objects_with_ordered_finalizers) {
784791
visitor.visit(&obj);
785792
}
786793

787-
graphTraversalMarking(stack, visitor);
794+
graphTraversalMarking(worklist, visitor);
788795
}
789796

790797
// Move objects around memory randomly. The purpose is to test whether the rest

src/gc/collector.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ class GCVisitorNoRedundancy : public GCVisitor {
8282
// Code to prototype a moving GC.
8383
//
8484

85-
class ReferenceMapStack;
85+
class ReferenceMapWorklist;
8686

8787
#if MOVING_GC
8888
#define MOVING_OVERRIDE override
@@ -93,12 +93,12 @@ class ReferenceMapStack;
9393
// Bulds the reference map, and also determine which objects cannot be moved.
9494
class GCVisitorPinning : public GCVisitorNoRedundancy {
9595
private:
96-
ReferenceMapStack* stack;
96+
ReferenceMapWorklist* worklist;
9797

9898
void _visit(void** ptr_address) MOVING_OVERRIDE;
9999

100100
public:
101-
GCVisitorPinning(ReferenceMapStack* stack) : stack(stack) {}
101+
GCVisitorPinning(ReferenceMapWorklist* worklist) : worklist(worklist) {}
102102
virtual ~GCVisitorPinning() {}
103103

104104
void visitPotential(void* p) MOVING_OVERRIDE;

src/gc/gc.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,9 @@ class Box;
4646
namespace gc {
4747

4848
class GCAllocation;
49-
class TraceStack;
49+
class TraversalWorklist;
5050

51-
// The base version of the GC visitor is used for marking, in conjuction with a TraceStack.
51+
// The base version of the GC visitor is used for marking, in conjuction with a TraversalWorklist.
5252
//
5353
// Conceptually, GCVisitor should be abstract and the 'marking' behavior should be specific
5454
// to a subclass of GCVisitor. However, that requires the use of virtual functions which
@@ -57,7 +57,7 @@ class TraceStack;
5757
// the virtualness property is #if'd out for the regular use case with only mark-and-sweep.
5858
class GCVisitor {
5959
private:
60-
TraceStack* stack = NULL;
60+
TraversalWorklist* worklist = NULL;
6161

6262
#if MOVING_GC
6363
virtual void _visit(void** ptr_address);
@@ -75,7 +75,7 @@ class GCVisitor {
7575

7676
public:
7777
GCVisitor() {}
78-
GCVisitor(TraceStack* stack) : stack(stack) {}
78+
GCVisitor(TraversalWorklist* worklist) : worklist(worklist) {}
7979
virtual ~GCVisitor() {}
8080

8181
#if MOVING_GC

0 commit comments

Comments
 (0)