Writing a compiler pass in joeq
is easy, once you learn a few basics. You should be familiar with the basic
operation of the visitors and the joeq code hierarchy before dealing with these
samples.
Here's a simple compiler pass
that counts all the quads it visits:
import joeq.Compiler.Quad.*; public class QuadCounter extends QuadVisitor.EmptyVisitor { public int count = 0; public void visitQuad(Quad q) { count++; }}
There's not a lot to say about this class.
The QuadVisitor interface specifies a vast number of
methods, and we only care about one of them (the most generic, which is always
invoked). Thus, we extend the associated EmptyVisitor instead of implementing the core
interface. The operation of the pass is fairly straightforward -- any time a
quad accepts this pass, we bump the counter.
This is all well and good, but how do we
run our pass on anything? As a QuadVisitor, we can run it on a code chunk of
any size -- a class, a method, a basic block, or even a single quad (though
that last isn't likely to be too interesting). To run this pass, we simply use
one of joeq.Main.Helper's
many runPass methods. We add a main method that reads in class names from the
command line and runs itself on those passes.
import joeq.Compiler.Quad.*;import joeq.Main.Helper;import joeq.Class.jq_Class; public class QuadCounter extends QuadVisitor.EmptyVisitor { public int count = 0; public void visitQuad(Quad q) { count++; } public static void main(String[] args) { jq_Class[] c = new jq_Class[args.length]; for (int i = 0; i < args.length; i++) { c[i] = (jq_Class)Helper.load(args[i]); } QuadCounter qc = new QuadCounter(); for (int i = 0; i < args.length; i++) { qc.count = 0; Helper.runPass(c[i], qc); System.out.println(c[i].getName()+" has "+ qc.count+" Quads."); } }}
What if you only wanted to count the
number of "move" instructions? The "visitQuad"
method matches all quads. The visitor interface also has other kinds of visit
methods that match specific quads; that is to say, they are only called on
quads that match a specific type. Here is an example of a visitor that counts
the number of instructions that load from memory and the number of instructions
that store into memory.
import joeq.Compiler.Quad.*; public class LoadStoreCounter extends QuadVisitor.EmptyVisitor { public int loadCount=0, storeCount=0; public void visitLoad(Quad q) { loadCount++; } public void visitStore(Quad q) { storeCount++; }}