Skip to content

Commit

Permalink
[refactor] Rename methods and members in the GC heap
Browse files Browse the repository at this point in the history
No change in functionality.
  • Loading branch information
Andy C committed Oct 5, 2022
1 parent e69f353 commit 5317d6f
Show file tree
Hide file tree
Showing 4 changed files with 44 additions and 41 deletions.
2 changes: 1 addition & 1 deletion mycpp/leaky_containers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ Str* Str::slice(int begin, int end) {
Str* result = AllocStr(new_len);
memcpy(result->data_, data_ + begin, new_len);

gHeap.AddRoot(result); // return value rooting
gHeap.RootOnReturn(result); // return value rooting
return result;
}

Expand Down
2 changes: 1 addition & 1 deletion mycpp/marksweep_heap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
// don't want some kind of STL iterator.
void RootSet::MarkRoots(MarkSweepHeap* heap) {
for (int i = 0; i < num_frames_; ++i) {
const std::vector<Obj*>& frame = roots_[i];
const std::vector<Obj*>& frame = stack_[i];
int n = frame.size();
for (int j = 0; j < n; ++j) {
// TODO: would be nice to do non-recursive marking
Expand Down
43 changes: 23 additions & 20 deletions mycpp/marksweep_heap.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,26 @@

class MarkSweepHeap; // forward decl for circular dep

// The set of objects where the mark and sweep algorithm starts. Terminology:
// to "root" an object means "add it to the root set".
class RootSet {
public:
explicit RootSet(int num_reserved) {
roots_.reserve(num_reserved); // e.g. 32 stack frames to start
stack_.reserve(num_reserved); // e.g. 32 stack frames to start
for (int i = 0; i < num_reserved; ++i) {
roots_.emplace_back(); // Construct std::vector frame IN PLACE.
roots_.back().reserve(16); // Reserve 16 rooted variables per frame.
stack_.emplace_back(); // Construct std::vector frame IN PLACE.
stack_.back().reserve(16); // Reserve 16 rooted variables per frame.
}
}

// Called on function entry
void PushScope() {
// Construct more std::vector frames if necessary. We reuse vectors to
// avoid constructing one on every function call.
int num_constructed = roots_.size();
int num_constructed = stack_.size();
if (num_frames_ >= num_constructed) {
roots_.emplace_back();
roots_.back().reserve(16);

stack_.emplace_back();
stack_.back().reserve(16);
#if 0
num_constructed = roots_.size();
log("num_frames_ %d, num_constructed %d", num_frames_, num_constructed);
Expand All @@ -39,10 +40,11 @@ class RootSet {
void PopScope() {
// Remove all roots owned by the top frame. We're REUSING frames, so not
// calling vector<>::pop().
roots_[num_frames_ - 1].clear();
stack_[num_frames_ - 1].clear();
num_frames_--;
}

// Called by MarkSweepHeap::OnProcessExit
void Clear() {
while (num_frames_ > 0) {
PopScope();
Expand All @@ -51,8 +53,8 @@ class RootSet {

// Called when returning a value
//
// TODO: might want RootOnReturn() vs. RootOnThrow()
void AddRoot(Obj* root) {
// TODO: need RootOnThrow() too
void RootOnReturn(Obj* root) {
if (root == nullptr) { // No reason to add it
return;
}
Expand All @@ -65,7 +67,7 @@ class RootSet {
}

// Owned by the frame BELOW
roots_[num_frames_ - 2].push_back(root);
stack_[num_frames_ - 2].push_back(root);
}

// For testing
Expand All @@ -77,17 +79,18 @@ class RootSet {
int NumRoots() {
int result = 0;
for (int i = 0; i < num_frames_; ++i) {
result += roots_[i].size();
result += stack_[i].size();
}
return result;
}

void MarkRoots(MarkSweepHeap* heap);

// This representation seems weird, but is appropriate since multiple stack
// frames are "in play" at once. That is, AddRoot() may mutate root_set_[1]
// while root_set_[2] is being pushed/popped/modified.
std::vector<std::vector<Obj*>> roots_;
// A stack of frames that's updated in parallel the call stack.
// This representation is appropriate since multiple stack frames are "in
// play" at once. That is, RootOnReturn() may mutate root_set_[1] while
// root_set_[2] is being pushed/popped/modified.
std::vector<std::vector<Obj*>> stack_;
int num_frames_ = 0; // frames 0 to N-1 are valid
};

Expand All @@ -97,11 +100,11 @@ class MarkSweepHeap {
MarkSweepHeap() : root_set_(32) {
}

void Init(); // default threshold
void Init(); // use default threshold
void Init(int collect_threshold);

//
// OLD ROOTING
// OLD Local Var Rooting
//

void PushRoot(Obj** p) {
Expand All @@ -117,8 +120,8 @@ class MarkSweepHeap {
//

// Hopefully this will get inlined away
void AddRoot(Obj* root) {
root_set_.AddRoot(root);
void RootOnReturn(Obj* root) {
root_set_.RootOnReturn(root);
// Make the object a root until the CALLER returns
}

Expand Down
38 changes: 19 additions & 19 deletions mycpp/marksweep_heap_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -207,25 +207,25 @@ TEST root_set_test() {
// Make sure it was initialized correctly

// 32 pre-allocated frames
ASSERT_EQ_FMT(32, static_cast<int>(r.roots_.capacity()), "%d");
ASSERT_EQ_FMT(32, static_cast<int>(r.roots_.size()), "%d");
ASSERT_EQ_FMT(32, static_cast<int>(r.stack_.capacity()), "%d");
ASSERT_EQ_FMT(32, static_cast<int>(r.stack_.size()), "%d");

// reserved 16 rooted objects per frame
for (int i = 0; i < 32; ++i) {
ASSERT_EQ_FMT(16, static_cast<int>(r.roots_[i].capacity()), "%d");
ASSERT_EQ_FMT(0, static_cast<int>(r.roots_[i].size()), "%d");
ASSERT_EQ_FMT(16, static_cast<int>(r.stack_[i].capacity()), "%d");
ASSERT_EQ_FMT(0, static_cast<int>(r.stack_[i].size()), "%d");
}

/*
Str* g() {
Str* ret = StrFromC("X");
gHeap.AddRoot(ret);
gHeap.RootOnReturn(ret);
return ret;
}
Str* f(Str* s, Str* t) {
Str* ret = str_concat(s, t);
gHeap.AddRoot(ret);
gHeap.RootOnReturn(ret);
return ret;
}
Expand All @@ -249,33 +249,33 @@ TEST root_set_test() {
ASSERT_EQ_FMT(2, r.NumFrames(), "%d");

// g() returns "X"
r.AddRoot(StrFromC("X"));
r.RootOnReturn(StrFromC("X"));
ASSERT_EQ_FMT(1, r.NumRoots(), "%d");
ASSERT_EQ_FMT(2, r.NumFrames(), "%d");
ASSERT_EQ_FMT(1, static_cast<int>(r.roots_[0].size()), "%d");
ASSERT_EQ_FMT(0, static_cast<int>(r.roots_[1].size()), "%d");
ASSERT_EQ_FMT(1, static_cast<int>(r.stack_[0].size()), "%d");
ASSERT_EQ_FMT(0, static_cast<int>(r.stack_[1].size()), "%d");

r.PopScope(); // g() return
// "X" is still live after foo() returns!
ASSERT_EQ_FMT(1, r.NumRoots(), "%d");
ASSERT_EQ_FMT(1, r.NumFrames(), "%d");
ASSERT_EQ_FMT(1, static_cast<int>(r.roots_[0].size()), "%d");
ASSERT_EQ_FMT(1, static_cast<int>(r.stack_[0].size()), "%d");

r.PushScope(); // another g() call
ASSERT_EQ_FMT(1, r.NumRoots(), "%d");
ASSERT_EQ_FMT(2, r.NumFrames(), "%d");

// g() returns "X" again
r.AddRoot(StrFromC("X"));
r.RootOnReturn(StrFromC("X"));
ASSERT_EQ_FMT(2, r.NumRoots(), "%d");
ASSERT_EQ_FMT(2, r.NumFrames(), "%d");
ASSERT_EQ_FMT(2, static_cast<int>(r.roots_[0].size()), "%d");
ASSERT_EQ_FMT(0, static_cast<int>(r.roots_[1].size()), "%d");
ASSERT_EQ_FMT(2, static_cast<int>(r.stack_[0].size()), "%d");
ASSERT_EQ_FMT(0, static_cast<int>(r.stack_[1].size()), "%d");

r.PopScope(); // another g() return
ASSERT_EQ_FMT(2, r.NumRoots(), "%d");
ASSERT_EQ_FMT(1, r.NumFrames(), "%d");
ASSERT_EQ_FMT(2, static_cast<int>(r.roots_[0].size()), "%d");
ASSERT_EQ_FMT(2, static_cast<int>(r.stack_[0].size()), "%d");

r.PopScope(); // main() return
ASSERT_EQ_FMT(0, r.NumFrames(), "%d");
Expand All @@ -290,11 +290,11 @@ TEST root_set_null_test() {
r.PushScope();
r.PushScope();

r.AddRoot(StrFromC("X"));
r.RootOnReturn(StrFromC("X"));
ASSERT_EQ_FMT(1, r.NumRoots(), "%d");

// Does NOT get added
r.AddRoot(nullptr);
r.RootOnReturn(nullptr);
ASSERT_EQ_FMT(1, r.NumRoots(), "%d");

r.PopScope();
Expand All @@ -310,7 +310,7 @@ TEST root_set_big_test() {
for (int i = 0; i < 100; ++i) {
r.PushScope();
for (int j = 0; j < 100; ++j) {
r.AddRoot(StrFromC("Y"));
r.RootOnReturn(StrFromC("Y"));
}
}

Expand All @@ -331,7 +331,7 @@ Str *g(Str *left, Str *right) {

// TODO: call str_concat, NewList, etc.
Str *ret = left;
gHeap.AddRoot(ret);
gHeap.RootOnReturn(ret);
return ret;
}

Expand All @@ -349,7 +349,7 @@ int count_old(Str* a, Str* b) {
}

// Just like above, but instead of rooting variables, we create a RootsScope instance.
// It doesn't return a heap-allocated object, so we don't need gHeap.AddRoot().
// It doesn't return a heap-allocated object, so we don't need gHeap.RootOnReturn().
// Functions that allocate like Alloc<T> are responsible for that.

int count_new(Str* a, Str* b) {
Expand Down

0 comments on commit 5317d6f

Please sign in to comment.