1+ #include " garbage_collection.hpp"
2+ #include < iostream>
3+ #include < list>
4+ #include < loguru.hpp>
5+ #include " environment.hpp"
6+ #include " scheme.hpp"
7+
8+ namespace scm {
9+
10+ // keep track of how many objects we've created in the lifetime of the program
11+ static int totalObjectCount{0 };
12+
13+ // keep track of all existing objects
14+ // std::vector<Collectable*> ObjectHeap;
15+
16+ // constructor and destructor for Collectable class
17+ Collectable::Collectable () : marked(false )
18+ {
19+ id = totalObjectCount++;
20+ // keep track of the newly created object
21+ ObjectHeap.push_back (this );
22+ DLOG_IF_F (
23+ INFO, LOG_GARBAGE_COLLECTION, " create Obj:%d (marked: %d)" , static_cast <int >(id), marked);
24+ }
25+
26+ Collectable::~Collectable ()
27+ {
28+ DLOG_IF_F (ERROR, LOG_GARBAGE_COLLECTION, " delete Obj:%d" , static_cast <int >(id));
29+ }
30+
31+ /* *
32+ * Marks a scheme object as not to be deleted during garbage collection.
33+ * Will recursively call itself in case of cons objects.
34+ * @param obj the pointer to an object that's to be marked.
35+ */
36+ void markSchemeObject (Object* obj)
37+ {
38+ switch (getTag (obj)) {
39+ // in most cases, simply mark the object
40+ case TAG_INT:
41+ case TAG_FLOAT:
42+ case TAG_STRING:
43+ case TAG_SYMBOL:
44+ case TAG_NIL:
45+ case TAG_TRUE:
46+ case TAG_FALSE:
47+ case TAG_VOID:
48+ case TAG_EOF:
49+ case TAG_FUNC_BUILTIN:
50+ case TAG_SYNTAX:
51+ obj->marked = true ;
52+ break ;
53+ // user functions consist of two cons objects, the argument and bodylist
54+ case TAG_FUNC_USER:
55+ markSchemeObject (getUserFunctionArgList (obj));
56+ markSchemeObject (getUserFunctionBodyList (obj));
57+ break ;
58+ // recur until we've reached the end of the list
59+ case TAG_CONS:
60+ markSchemeObject (getCar (obj));
61+ markSchemeObject (getCdr (obj));
62+ break ;
63+
64+ default :
65+ schemeThrow (" tag " + std::to_string (obj->tag ) + " isn't handled yet" );
66+ break ;
67+ }
68+ };
69+
70+ /* *
71+ * Mark all objects reachable from a given environment as not to be collected.
72+ * @param env the environment from which an object needs to be reachable in order to be accepted
73+ */
74+ void mark (Environment& env)
75+ {
76+ for (auto & binding : env.bindings ) {
77+ DLOG_IF_F (INFO,
78+ LOG_GARBAGE_COLLECTION,
79+ " marking binding %s | %s" ,
80+ binding.first .c_str (),
81+ toString (binding.second ).c_str ());
82+ markSchemeObject (binding.second );
83+ }
84+ }
85+
86+ /* *
87+ * Delete all objects that weren't marked or aren't essential.
88+ */
89+ void sweep ()
90+ {
91+ int nObjectsBefore{static_cast <int >(ObjectHeap.size ())};
92+ for (auto i = ObjectHeap.begin (); i != ObjectHeap.end ();) {
93+ if (!(*i)->marked && !(*i)->essential ) {
94+ DLOG_IF_F (INFO,
95+ LOG_GARBAGE_COLLECTION,
96+ " delete %s %s" ,
97+ tagToString (getTag ((Object*)(*i))).c_str (),
98+ toString ((Object*)(*i)).c_str ());
99+ // TODO: this doesn't seem to work yet -> no deleting as of yet :)
100+ // delete *i;
101+ i = ObjectHeap.erase (i);
102+ }
103+ else {
104+ DLOG_IF_F (INFO,
105+ LOG_GARBAGE_COLLECTION,
106+ " keep %s %s" ,
107+ tagToString (((Object*)(*i))->tag ).c_str (),
108+ toString ((Object*)(*i)).c_str ());
109+ (*i)->marked = false ;
110+ ++i;
111+ }
112+ }
113+ int nObjectsAfter{static_cast <int >(ObjectHeap.size ())};
114+ DLOG_IF_F (WARNING,
115+ LOG_GARBAGE_COLLECTION,
116+ " cleaned up %d/%d objects" ,
117+ nObjectsBefore - nObjectsAfter,
118+ nObjectsBefore);
119+ }
120+
121+ /* *
122+ * Check which objects are still reachable from a given environment and delete the rest.
123+ * Implementation of a simple mark and sweep algorithm.
124+ * @param env the environment from which the objects need to be reachable in order not to be
125+ * deleted.
126+ */
127+ void markAndSweep (Environment& env)
128+ {
129+ mark (env);
130+ sweep ();
131+ }
132+
133+ } // namespace scm
0 commit comments