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.
10 // The following auxiliary class keeps track of allocation and finalization.
14 static int allocation_count;
15 static int deallocation_count;
16 LOGGER() { allocation_count++; }
17 ~LOGGER() { deallocation_count++; }
20 int LOGGER::allocation_count = 0;
21 int LOGGER::deallocation_count = 0;
24 // Define an algebraic datatype. Currently, rewriting can only be
25 // performed on datatypes(and not views) in Prop.
26 // If replacement is to be performed on a datatype, then it should
27 // be declared using the ``rewrite'' qualifier.
28 // In this example, we'll use garbage collection with rewriting.
30 // We'll inherit from LOGGER so that allocation and finalization
31 // of each EXP cell is logged.
33 datatype EXP : LOGGER :: collectable rewrite
44 // Datatype instantiation generates any additional methods and definitions.
45 // In this case garbage collection tracing methods are generated.
46 // As always, this should be placed in an implementation file.
48 instantiate datatype EXP;
51 // Define a method that prints an expression. This is a simple
52 // inductive definition
54 ostream& operator << (ostream& f, EXP e)
56 om: { return f << "om"; }
57 | num i: { return f << i; }
58 | var v: { return f << v; }
59 | add(a,b): { return f << '(' << a << " + " << b << ')'; }
60 | sub(a,b): { return f << '(' << a << " - " << b << ')'; }
61 | mul(a,b): { return f << '(' << a << " * " << b << ')'; }
62 | div(a,b): { return f << '(' << a << " / " << b << ')'; }
67 // Define the interface to a ``rewriting class.'' A rewriting class
68 // is simply a C++ class with rewriting rules attached. In real programs
69 // this definition should be placed in some definition (i.e. .ph) files.
71 // In parenthesis, we must list all datatypes involved. Unlike
72 // simple pattern matching, rewriting can involve a set of mutually
73 // recursive (or mutually exclusive, if desired) datatype definitions.
74 // So in general this is a comma delimited list.
76 // In this example it involves only the datatype EXP.
78 rewrite class Simplify (EXP)
79 { // nothing here for now.
85 // Now we define the rewriting rules in the rewriting class Simplify. These
86 // rules should be placed in an implementation file (.pcc, .pC, .pc++ etc).
88 // In this brief sample class we have some rules that perform
89 // simple constant folding and strength reduction.
91 // Currently, all the rules for a rewrite class must be placed in
92 // the same rewrite construct. This will probably change in the future
93 // once I work out the details on incremental tree automata compilation.
96 add (num 0, x): rewrite(x);
97 | add (x, num 0): rewrite(x);
98 | sub (x, num 0): rewrite(x);
99 | mul (x, num 0): rewrite(num(0));
100 | mul (num 0, x): rewrite(num(0));
101 | mul (x, num 1): rewrite(x);
102 | mul (num 1, x): rewrite(x);
103 | mul (x, num 2): rewrite(add(x,x));
104 | mul (num 2, x): rewrite(add(x,x));
105 | div (x, num 1): rewrite(x);
106 | add (num x, num y): rewrite(num(x + y));
107 | sub (num x, num y): rewrite(num(x - y));
108 | mul (num x, num y): rewrite(num(x * y));
109 | div (num x, num y) where (y != 0): rewrite(num(x / y));
110 | div (_, num 0): { /* cout << "Division by zero!\n"; */ }
111 | div (zero as num 0, x): rewrite(zero);
115 // Now defines the function that uses all this stuff.
120 // Instantiate a rewriting class
125 for (int trials = 1; trials < 10000; trials++) {
127 // (0 + x * 2) / (1 * 5 + 1 * 3) / (0 / y);
129 t1 = div(div(add(num(0), mul(var('x'),num(2))),
130 add(mul(num(1), num(5)),mul(num(1),num(3)))),
131 div(num(0),var('y')));
135 // Rewrite the big term above.
137 // cout << "Before: " << term << '\n';
139 // cout << "After: " << term << '\n';
142 // Rewrite it again. It should have no effect since the term
143 // is already in normal form.
146 // cout << "Again (should have no effect): " << term << '\n';
149 // Rewrite some other term.
151 term2 = add(sub(num(3),num(3)), var('z'));
152 // cout << "Before: " << term2 << '\n';
154 // cout << "After: " << term2 << '\n';
161 // Turn on finalization
163 GC::get_default_gc().set_finalization(true);
165 cout << "Now performing some rewrites and generating some garbage.\n"
166 "(See also the test 'test_rc1')\n" << flush;
167 // GC::get_default_gc().set_verbosity(0);
169 cout << "Finished. Now I'll force one more GC to clean up.\n"
170 "There should be at most a few kilobytes of retention at the end.\n"
171 "The GC should be able to recognized a large part of the heap as\n"
172 "garbage. See below:\n";
173 // GC::get_default_gc().set_verbosity(1);
174 GC::garbage_collect();
175 cout << "The following allocation count should be very close to the\n"
176 "finalization count. If they are very far apart that means\n"
177 "something is wrong.\n"
178 << "Allocation count = " << LOGGER::allocation_count << '\n'
179 << "Number of finalizations = " << LOGGER::deallocation_count << '\n';
180 if (GC::get_default_gc().statistics().bytes_used <= 1024)
181 cout << "Seems like it's working well for your platform. Lucky dog!\n";