Permalink
Browse files

Implement Mark and Sweep GC

  • Loading branch information...
doublec committed May 20, 2009
1 parent a617a14 commit fdc3dd7a317000bb4d70bf2b02037066549898ff
Showing with 222 additions and 6 deletions.
  1. +1 −0 README
  2. +138 −0 cf.cpp
  3. +69 −6 cf.h
  4. +2 −0 main.cpp
  5. +5 −0 socket.cpp
  6. +7 −0 threads.cpp
View
1 README
@@ -178,6 +178,7 @@ foldl - ( seq seed q -- seq ) left fold
foldr - ( seq seed q -- seq ) right fold
if - ( bool then else -- )
? - ( seq elt -- index ) find
+gc - ( -- ) Perform garbage collection
Numbers can be floats or integers. Integers can be of any length. For example:
View
138 cf.cpp
@@ -209,6 +209,90 @@ static XYObject* dd_power(XYSequence* lhs, XYSequence* rhs) {
return list;
}
+// GCObject
+GCObject::GCObject() :
+ mMarked(false) {
+ GarbageCollector::GC.addObject(this);
+}
+
+GCObject::~GCObject() {
+}
+
+void GCObject::mark() {
+ if (!mMarked) {
+ mMarked = true;
+ markChildren();
+ }
+}
+
+void GCObject::markChildren() {
+}
+
+// GarbageCollector
+GarbageCollector GarbageCollector::GC;
+
+void GarbageCollector::collect() {
+ using namespace boost::posix_time;
+ unsigned int start = (microsec_clock::universal_time() - ptime(min_date_time)).total_milliseconds();
+
+ for (ObjectSet::iterator it = mRoots.begin();
+ it != mRoots.end();
+ ++it)
+ (*it)->mark();
+
+ cout << "GC: " << mHeap.size() << " objects in heap" << endl;
+ sweep();
+
+ unsigned int end = (microsec_clock::universal_time() - ptime(min_date_time)).total_milliseconds();
+ cout << "GC: " << (end-start) << " milliseconds" << endl;
+}
+
+void GarbageCollector::addRoot(GCObject* root) {
+ mRoots.insert(root);
+}
+
+void GarbageCollector::removeRoot(GCObject* root) {
+ mRoots.erase(root);
+}
+
+void GarbageCollector::addObject(GCObject* o) {
+ mHeap.insert(o);
+}
+
+void GarbageCollector::removeObject(GCObject* o) {
+ mHeap.erase(o);
+}
+
+void GarbageCollector::sweep() {
+ unsigned int live = 0;
+ unsigned int dead = 0;
+ unsigned int total = 0;
+ vector<ObjectSet::iterator> erase;
+ for (ObjectSet::iterator it = mHeap.begin();
+ it != mHeap.end();
+ ++it) {
+ GCObject* p = *it;
+ total++;
+ if (p->mMarked) {
+ p->mMarked = false;
+ ++live;
+ }
+ else {
+ erase.push_back(it);
+ }
+ }
+ dead = erase.size();
+ for (vector<ObjectSet::iterator>::iterator it = erase.begin();
+ it != erase.end();
+ ++it) {
+ GCObject* p = **it;
+ mHeap.erase(*it);
+ delete p;
+ }
+ cout << "GC: " << live << " objects live after sweep" << endl;
+ cout << "GC: " << dead << " objects dead after sweep" << endl;
+}
+
// XYObject
XYObject::XYObject() { }
@@ -557,6 +641,7 @@ DD_IMPL(XYSequence, subtract)
DD_IMPL(XYSequence, multiply)
DD_IMPL(XYSequence, divide)
DD_IMPL(XYSequence, power)
+
int XYSequence::compare(XYObject* rhs) {
XYSequence* o = dynamic_cast<XYSequence*>(rhs);
if (!o)
@@ -590,6 +675,11 @@ XYList::XYList(InputIterator first, InputIterator last) {
mList.assign(first, last);
}
+void XYList::markChildren() {
+ for (iterator it = mList.begin(); it != mList.end(); ++it)
+ (*it)->mark();
+}
+
void XYList::print(ostringstream& stream, CircularSet& seen, bool parse) const {
if (seen.find(this) != seen.end()) {
stream << "(circular)";
@@ -681,6 +771,10 @@ XYSlice::XYSlice(XYSequence* original,
}
}
+void XYSlice::markChildren() {
+ mOriginal->mark();
+}
+
void XYSlice::print(ostringstream& stream, CircularSet& seen, bool parse) const {
if (seen.find(this) != seen.end()) {
stream << "(circular)";
@@ -761,6 +855,11 @@ XYJoin::XYJoin(XYSequence* first, XYSequence* second)
mSequences.push_back(second);
}
+void XYJoin::markChildren() {
+ for (iterator it = mSequences.begin(); it != mSequences.end(); ++it)
+ (*it)->mark();
+}
+
void XYJoin::print(ostringstream& stream, CircularSet& seen, bool parse) const {
if (seen.find(this) != seen.end()) {
stream << "(circular)";
@@ -1821,6 +1920,11 @@ static void primitive_find(XY* xy) {
xy->mX.push_back(new XYInteger(i));
}
+// gc gc [X Y] -> [X Y]
+static void primitive_gc(XY* xy) {
+ GarbageCollector::GC.collect();
+}
+
// XYTimeLimit
XYTimeLimit::XYTimeLimit(unsigned int milliseconds) :
mMilliseconds(milliseconds) {
@@ -1937,6 +2041,40 @@ XY::XY(boost::asio::io_service& service) :
mP["foldr"] = new XYPrimitive("foldr", primitive_foldr);
mP["if"] = new XYPrimitive("if", primitive_if);
mP["?"] = new XYPrimitive("?", primitive_find);
+ mP["gc"] = new XYPrimitive("gc", primitive_gc);
+}
+
+void XY::markChildren() {
+ for (XYWaitingList::iterator it = mWaiting.begin();
+ it != mWaiting.end();
+ ++it) {
+ (*it)->mark();
+ }
+ for (XYEnv::iterator it = mEnv.begin();
+ it != mEnv.end();
+ ++it) {
+ (*it).second->mark();
+ }
+ for (XYEnv::iterator it = mP.begin();
+ it != mP.end();
+ ++it) {
+ (*it).second->mark();
+ }
+ for (XYStack::iterator it = mX.begin();
+ it != mX.end();
+ ++it) {
+ (*it)->mark();
+ }
+ for (XYQueue::iterator it = mY.begin();
+ it != mY.end();
+ ++it) {
+ (*it)->mark();
+ }
+ for (XYLimits::iterator it = mLimits.begin();
+ it != mLimits.end();
+ ++it) {
+ (*it)->mark();
+ }
}
void XY::stdioHandler(boost::system::error_code const& err) {
View
75 cf.h
@@ -29,13 +29,68 @@ class XYSequence;
virtual XYObject* name(XYInteger* lhs); \
virtual XYObject* name(XYSequence* lhs)
-// Objects in XY are garbage collected using the Boehm Garbage
-// Collector.
-//
+// Base class for all objects that are tracked by
+// the garbage collector.
+class GCObject {
+ public:
+
+ // For mark and sweep algorithm. When a GC occurs
+ // all live objects are traversed and mMarked is
+ // set to true. This is followed by the sweep phase
+ // where all unmarked objects are deleted.
+ bool mMarked;
+
+ public:
+ GCObject();
+ virtual ~GCObject();
+
+ // Mark the object and all its children as live
+ void mark();
+
+ // Overridden by derived classes to call mark()
+ // on objects referenced by this object. The default
+ // implemention does nothing.
+ virtual void markChildren();
+};
+
+// Garbage Collector. Implements mark and sweep GC algorithm.
+class GarbageCollector {
+ public:
+ // A collection of all active heap objects.
+ typedef std::set<GCObject*> ObjectSet;
+ ObjectSet mHeap;
+
+ // Collection of objects that are scanned for garbage.
+ ObjectSet mRoots;
+
+ // Global garbage collector object
+ static GarbageCollector GC;
+
+ public:
+ // Perform garbage collection
+ void collect();
+
+ // Add a root object to the collector.
+ void addRoot(GCObject* root);
+
+ // Remove a root object from the collector.
+ void removeRoot(GCObject* root);
+
+ // Add an heap allocated object to the collector.
+ void addObject(GCObject* o);
+
+ // Remove a heap allocated object from the collector.
+ void removeObject(GCObject* o);
+
+ // Go through all objects in the heap, unmarking the live
+ // objects and destroying the unreferenced ones.
+ void sweep();
+};
+
// Base class for all objects in the XY system. Anything
// stored on the stack, in the queue, in the the environment
// must be derived from this.
-class XYObject
+class XYObject : public GCObject
{
public:
XYObject();
@@ -246,6 +301,8 @@ class XYList : public XYSequence
public:
XYList();
template <class InputIterator> XYList(InputIterator first, InputIterator last);
+
+ virtual void markChildren();
virtual void print(std::ostringstream& stream, CircularSet& seen, bool parse) const;
virtual void eval1(XY* xy);
virtual size_t size();
@@ -274,6 +331,8 @@ class XYSlice : public XYSequence
XYSlice(XYSequence* original,
int start,
int end);
+
+ virtual void markChildren();
virtual void print(std::ostringstream& stream, CircularSet& seen, bool parse) const;
virtual void eval1(XY* xy);
virtual size_t size();
@@ -301,6 +360,8 @@ class XYJoin : public XYSequence
public:
XYJoin() { }
XYJoin(XYSequence* first, XYSequence* second);
+
+ virtual void markChildren();
virtual void print(std::ostringstream& stream, CircularSet& seen, bool parse) const;
virtual void eval1(XY* xy);
virtual size_t size();
@@ -332,7 +393,7 @@ class XYPrimitive : public XYObject
// XY program. Limit examples might be a requirement to run
// within a certain number of ticks, time period or
// memory size.
-class XYLimit {
+class XYLimit : public GCObject {
public:
// Called when execution starts so the limit checker can
// initialize things like initial start time or tick count.
@@ -398,7 +459,7 @@ typedef std::vector<XY*> XYWaitingList;
// Holds the environment, stack and queue
// and provides methods to step through or run
// the interpreter.
-class XY {
+class XY : public GCObject {
public:
// io service for handling asynchronous events
// The lifetime of the service is controlled by
@@ -448,6 +509,8 @@ class XY {
XY(boost::asio::io_service& service);
virtual ~XY() { }
+ virtual void markChildren();
+
// Handler for asynchronous i/o events
void stdioHandler(boost::system::error_code const& err);
View
@@ -99,6 +99,8 @@ int main(int argc, char* argv[]) {
// limit exception is thrown.
//xy->mLimits.push_back(new XYTimeLimit(10000));
+ GarbageCollector::GC.addRoot(xy);
+ GarbageCollector::GC.collect();
xy->print();
cout << "ok ";
cout.flush();
View
@@ -44,6 +44,7 @@ class XYLineChannel : public XYObject {
public:
XYLineChannel(XYSocket* socket);
+ virtual void markChildren();
void handleRead(boost::system::error_code const& err);
virtual void print(std::ostringstream& stream, CircularSet& seen, bool parse) const;
@@ -115,6 +116,10 @@ XYLineChannel::XYLineChannel(XYSocket* socket) :
boost::asio::placeholders::error));
}
+void XYLineChannel::markChildren() {
+ mSocket->mark();
+}
+
void XYLineChannel::handleRead(boost::system::error_code const& err) {
if (!err) {
// cout << "Got some data" << endl;
View
@@ -16,6 +16,7 @@ class XYThread : public XYObject {
public:
XYThread(XY* xy, XY* parent);
+ virtual void markChildren();
void spawn();
virtual void print(std::ostringstream& stream, CircularSet& seen, bool parse) const;
@@ -30,6 +31,12 @@ XYThread::XYThread(XY* xy, XY* parent) :
{
}
+void XYThread::markChildren() {
+ mXY->mark();
+ if (mParent)
+ mParent->mark();
+}
+
void XYThread::spawn() {
mXY->mRepl = false;
for(XYLimits::iterator it = mXY->mLimits.begin(); it != mXY->mLimits.end(); ++it) {

0 comments on commit fdc3dd7

Please sign in to comment.