Getting started writing a compiler pass with joeq

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++; }
}

<-- previous home next -->