aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gc.cpp83
-rw-r--r--gc.h31
2 files changed, 114 insertions, 0 deletions
diff --git a/gc.cpp b/gc.cpp
new file mode 100644
index 0000000..4a3dd89
--- /dev/null
+++ b/gc.cpp
@@ -0,0 +1,83 @@
+#include "gc.h"
+#include "exc.h"
+#include "consts.h"
+
+#ifdef GC_DEBUG
+#include <cstdio>
+typedef unsigned long long ull;
+#endif
+
+static EvalObj *gcq[GC_QUEUE_SIZE];
+
+GarbageCollector::PendingEntry::PendingEntry(
+ EvalObj *_obj, PendingEntry *_next) : obj(_obj), next(_next) {}
+
+
+void GarbageCollector::expose(EvalObj *ptr) {
+ bool flag = mapping.count(ptr);
+ if (flag)
+ {
+ if (!--mapping[ptr])
+ {
+#ifdef GC_DEBUG
+ fprintf(stderr, "GC: 0x%llx pending. \n", (ull)ptr);
+#endif
+ pending_list = new PendingEntry(ptr, pending_list);
+ if (++pend_cnt == GC_QUEUE_SIZE >> 1)
+ force(); // the gc queue may overflow
+ }
+ }
+}
+
+void GarbageCollector::force() {
+ EvalObj **l = gcq, **r = l;
+ for (PendingEntry *p = pending_list, *np; p; p = np)
+ {
+ np = p->next;
+ *r++ = p->obj;
+ delete p;
+ } // fetch the pending pointers in the list
+ // clear the list
+ pending_list = NULL;
+
+#ifdef GC_DEBUG
+ size_t cnt = 0;
+ fprintf(stderr, "GC: Forcing the clear process...\n");
+#endif
+ for (; l != r; l++)
+ {
+#ifdef GC_DEBUG
+ fprintf(stderr, "GC: destroying space 0x%llx. \n", (ull)*l);
+ cnt++;
+#endif
+ delete *l;
+ // maybe it's a complex structure,
+ // so that more pointers are reported
+ for (PendingEntry *p = pending_list, *np; p; p = np)
+ {
+ np = p->next;
+ *r++ = p->obj;
+ if (r == gcq + GC_QUEUE_SIZE)
+ throw NormalError(RUN_ERR_GC_OVERFLOW);
+ delete p;
+ }
+ pending_list = NULL;
+ }
+#ifdef GC_DEBUG
+ fprintf(stderr, "GC: Forced clear, %lu objects are freed\n", cnt);
+#endif
+}
+
+EvalObj *GarbageCollector::attach(EvalObj *ptr) {
+ if (!ptr) return NULL; // NULL pointer
+ bool flag = mapping.count(ptr);
+ if (flag) mapping[ptr]++;
+ else mapping[ptr] = 1;
+#ifdef GC_DEBUG
+ fprintf(stderr, "GC: 0x%llx attached. count = %lu \"%s\"\n",
+ (ull)ptr, mapping[ptr], ptr->ext_repr().c_str());
+#endif
+ return ptr; // passing through
+}
+
+GarbageCollector gc;
diff --git a/gc.h b/gc.h
new file mode 100644
index 0000000..417462f
--- /dev/null
+++ b/gc.h
@@ -0,0 +1,31 @@
+#ifndef GC_H
+#define GC_H
+
+#include "model.h"
+#include <map>
+
+const int GC_QUEUE_SIZE = 262144;
+
+typedef std::map<EvalObj*, size_t> EvalObj2Int;
+
+class GarbageCollector {
+
+ struct PendingEntry {
+ EvalObj *obj;
+ PendingEntry *next;
+ PendingEntry(EvalObj *obj, PendingEntry *next);
+ };
+
+ EvalObj2Int mapping;
+ size_t pend_cnt;
+ PendingEntry *pending_list;
+
+ public:
+ void force();
+ void expose(EvalObj *ptr);
+ EvalObj *attach(EvalObj *ptr);
+};
+
+extern GarbageCollector gc;
+
+#endif