2 // Testing finalization with garbage collection.
3 // We use the class BGC_F (BGC with finalization) for garbage collection.
4 // In addition of reclaiming garbage, BGC_F will also call the finalization
5 // method (the destructor) for each object freed.
8 #include <AD/gc/markswp.h>
10 MarkSweepGC marksweep_gc;
13 // The following auxiliary class keeps track of allocation and finalization.
17 static int allocation_count;
18 static int deallocation_count;
19 LOGGER() { allocation_count++; }
20 ~LOGGER() { deallocation_count++; }
23 int LOGGER::allocation_count = 0;
24 int LOGGER::deallocation_count = 0;
27 // Define an algebraic datatype. Currently, rewriting can only be
28 // performed on datatypes(and not views) in Prop.
29 // If replacement is to be performed on a datatype, then it should
30 // be declared using the ``rewrite'' qualifier.
31 // In this example, we'll use garbage collection with rewriting.
33 // We'll inherit from LOGGER so that allocation and finalization
34 // of each EXP cell is logged.
36 datatype EXP : LOGGER :: collectable rewrite
47 // Datatype instantiation generates any additional methods and definitions.
48 // In this case garbage collection tracing methods are generated.
49 // As always, this should be placed in an implementation file.
51 instantiate datatype EXP;
54 // Define a method that prints an expression. This is a simple
55 // inductive definition
57 ostream& operator << (ostream& f, EXP e)
59 om: { return f << "om"; }
60 | num i: { return f << i; }
61 | var v: { return f << v; }
62 | add(a,b): { return f << '(' << a << " + " << b << ')'; }
63 | sub(a,b): { return f << '(' << a << " - " << b << ')'; }
64 | mul(a,b): { return f << '(' << a << " * " << b << ')'; }
65 | div(a,b): { return f << '(' << a << " / " << b << ')'; }
70 // Define the interface to a ``rewriting class.'' A rewriting class
71 // is simply a C++ class with rewriting rules attached. In real programs
72 // this definition should be placed in some definition (i.e. .ph) files.
74 // In parenthesis, we must list all datatypes involved. Unlike
75 // simple pattern matching, rewriting can involve a set of mutually
76 // recursive (or mutually exclusive, if desired) datatype definitions.
77 // So in general this is a comma delimited list.
79 // In this example it involves only the datatype EXP.
81 rewrite class Simplify (EXP)
82 { // nothing here for now.
88 // Now we define the rewriting rules in the rewriting class Simplify. These
89 // rules should be placed in an implementation file (.pcc, .pC, .pc++ etc).
91 // In this brief sample class we have some rules that perform
92 // simple constant folding and strength reduction.
94 // Currently, all the rules for a rewrite class must be placed in
95 // the same rewrite construct. This will probably change in the future
96 // once I work out the details on incremental tree automata compilation.
99 add (num 0, x): rewrite(x);
100 | add (x, num 0): rewrite(x);
101 | sub (x, num 0): rewrite(x);
102 | mul (x, num 0): rewrite(num(0));
103 | mul (num 0, x): rewrite(num(0));
104 | mul (x, num 1): rewrite(x);
105 | mul (num 1, x): rewrite(x);
106 | mul (x, num 2): rewrite(add(x,x));
107 | mul (num 2, x): rewrite(add(x,x));
108 | div (x, num 1): rewrite(x);
109 | add (num x, num y): rewrite(num(x + y));
110 | sub (num x, num y): rewrite(num(x - y));
111 | mul (num x, num y): rewrite(num(x * y));
112 | div (num x, num y) where (y != 0): rewrite(num(x / y));
113 | div (_, num 0): { /* cout << "Division by zero!\n"; */ }
114 | div (zero as num 0, x): rewrite(zero);
118 // Now defines the function that uses all this stuff.
123 // Instantiate a rewriting class
128 for (int trials = 1; trials < 10000; trials++) {
130 // (0 + x * 2) / (1 * 5 + 1 * 3) / (0 / y);
132 t1 = div(div(add(num(0), mul(var('x'),num(2))),
133 add(mul(num(1), num(5)),mul(num(1),num(3)))),
134 div(num(0),var('y')));
138 // Rewrite the big term above.
140 // cout << "Before: " << term << '\n';
142 // cout << "After: " << term << '\n';
145 // Rewrite it again. It should have no effect since the term
146 // is already in normal form.
149 // cout << "Again (should have no effect): " << term << '\n';
152 // Rewrite some other term.
154 term2 = add(sub(num(3),num(3)), var('z'));
155 // cout << "Before: " << term2 << '\n';
157 // cout << "After: " << term2 << '\n';
163 GC::set_default_gc(marksweep_gc);
165 // Turn on finalization
167 GC::get_default_gc().set_finalization(true);
169 cout << "Now performing some rewrites and generating some garbage.\n"
170 "(See also the test 'test_rc1')\n" << flush;
171 // GC::get_default_gc().set_verbosity(0);
173 cout << "Finished. Now I'll force one more GC to clean up.\n"
174 "There should be at most a few kilobytes of retention at the end.\n"
175 "The GC should be able to recognized a large part of the heap as\n"
176 "garbage. See below:\n";
177 // GC::get_default_gc().set_verbosity(1);
178 GC::garbage_collect();
179 cout << "The following allocation count should be very close to the\n"
180 "finalization count. If they are very far apart that means\n"
181 "something is wrong.\n"
182 << "Allocation count = " << LOGGER::allocation_count << '\n'
183 << "Number of finalizations = " << LOGGER::deallocation_count << '\n';
184 if (GC::get_default_gc().statistics().bytes_used <= 1024)
185 cout << "Seems like it's working well for your platform. Lucky dog!\n";