[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

profiling questions



Hi.

I'm trying to compute the number of silent stores in a Java program. A silent store occurs when the value stored is identical to the value already there. I have three questions:

Q1) Why does the single variable "y" in the following code get split into "b1" and "b2" in the Jimple representation:

public class HelloWorld {
   public static void main(String[] args) {
       int y;
       y = 2;
       y = 2;
   }
}

-->

public class HelloWorld extends java.lang.Object
{

   public void <init>()
   {
       HelloWorld r0;

       r0 := @this: HelloWorld;
       specialinvoke r0.<java.lang.Object: void <init>()>();
       return;
   }

   public static void main(java.lang.String[] )
   {
       java.lang.String[] r0;
       byte b0, b1;

       r0 := @parameter0: java.lang.String[];
       b0 = 2;
       b1 = 2;
       return;
   }
}

Q2) How can I test whether a variable (register?) has been initialized at runtime. Currently, for the Jimple code:

b0 = 2;

I can transform it to produce:

  if b0 == null goto label0;
  if b0 != 2 goto label0;
  tmp = <HelloWorld: long silentStoreCounter>;
  tmp = tmp + 1L;
  <HelloWorld: long silentStoreCounter> = tmp;
label0:
  b0 = 2;

However, even with that null test there, I still get the following error at runtime:

Exception in thread "main" java.lang.VerifyError: (class: HelloWorld, method: main signature: ([Ljava/lang/String;)V) Accessing value from uninitialized register 1

Is there a a way to test? Or do I have to keep track of which variables have been initialized inside my internalTransform() method? If there is a way to test, can I use it on statics and fields as well as locals?

Q3) Can I otherwise use NeqExpr to compare any two values? Does this work for object references or do I have to do something else? I want to know if the operands actually refer to the same object, so I don't think EquivTo() works here.

Cheers,
Chris

Attached please find the files I am talking about.
public class HelloWorld {
    
    //static int x;

    public static void main(String[] args) {
	//System.out.println("Hello World!");
	int y;
	/*x = 5;
	y = x;
	if (y == 5)
	    y = x;
	*/
	y = 2;
	y = 2;
    }
}
import soot.*;
import soot.jimple.*;
import soot.jimple.internal.*;
import soot.util.*;
import java.io.*;
import java.util.*;

public class SilentStoreMain {
    
    public static void main(String[] args) {

	if (args.length == 0) {
            System.out.println(
              "Syntax: java SilentStoreMain [soot options] classfile");
            System.exit(0);
        }            
        Scene.v().getPack("jtp").add(
          new Transform("jtp.silentstore", SilentStoreTransformer.v()));
        soot.Main.main(args);
    }
}

/**
   This class transforms a body to count the number of silent stores.
*/

class SilentStoreTransformer extends BodyTransformer {

    /* standard BodyTransformer stuff */
    private static SilentStoreTransformer instance = 
	new SilentStoreTransformer();
    private SilentStoreTransformer() {}
    public static SilentStoreTransformer v() { return instance; }
    public String getDeclaredOptions() { return super.getDeclaredOptions(); }
    private boolean addedFieldsToMainClassAndLoadedPrintStream = false;
    private SootClass javaIoPrintStream;

    /* the next three methods exist so that the number of silent stores or the
       number of stores can be printed out
    */

    private Local addTmpRef(Body body) {
        Local tmpRef = Jimple.v().newLocal(
	  "tmpRef", RefType.v("java.io.PrintStream"));
        body.getLocals().add(tmpRef);
        return tmpRef;
    }
     
    private Local addTmpLong(Body body) {
        Local tmpLong = Jimple.v().newLocal("tmpLong", LongType.v()); 
        body.getLocals().add(tmpLong);
        return tmpLong;
    }

    private void addPrintCounter(Chain units,
				 Stmt s,
				 SootField counter,
				 Local tmpRef,
				 Local tmpLong) {
	
        // insert "tmpRef = java.lang.System.out;" 
        units.insertBefore(Jimple.v().newAssignStmt( 
	  tmpRef, Jimple.v().newStaticFieldRef( 
	    Scene.v().getField(
              "<java.lang.System: java.io.PrintStream out>"))), s);

        // insert "tmpLong = counter;" 
        units.insertBefore(Jimple.v().newAssignStmt(
	  tmpLong, Jimple.v().newStaticFieldRef(counter)), s);
            
        // insert "tmpRef.println(tmpLong);" 
        SootMethod toCall = javaIoPrintStream.getMethod("void println(long)");
        units.insertBefore(Jimple.v().newInvokeStmt(
	  Jimple.v().newVirtualInvokeExpr(tmpRef, toCall, tmpLong)), s);
    }

    private void addCounterIncrement(Chain units,
				     Stmt s,
				     SootField counter,
				     Local tmpLocal) {
	
	AssignStmt toAdd1 = Jimple.v().newAssignStmt(tmpLocal, 
	  Jimple.v().newStaticFieldRef(counter));
	AssignStmt toAdd2 = Jimple.v().newAssignStmt(tmpLocal,
	  Jimple.v().newAddExpr(tmpLocal, LongConstant.v(1L)));
	AssignStmt toAdd3 = Jimple.v().newAssignStmt(
          Jimple.v().newStaticFieldRef(counter),tmpLocal);

	// insert "tmpLocal = counter;"
	units.insertBefore(toAdd1, s);
                        
	// insert "tmpLocal = tmpLocal + 1L;" 
	units.insertBefore(toAdd2, s);

	// insert "counter = tmpLocal;" 
	units.insertBefore(toAdd3, s);
    }

    private boolean addSilentStoreTest(Chain units, AssignStmt s,
				       SootField counter,
				       Local tmpLocal) {
	
	/* inserts a test to see if a store is silent before an AssignStmt,
	   and returns true if the insertion worked properly.
	*/

	/* create a new ImmediateBox with a dummy value */
	ImmediateBox iBox = new ImmediateBox(LongConstant.v(1L));

	/* now test that the left and right ops can fit in the box */
	if (iBox.canContainValue(s.getLeftOp()) && 
	    iBox.canContainValue(s.getRightOp())) {
	    
	    EqExpr cond1 = 
		Jimple.v().newEqExpr(s.getLeftOp(),NullConstant.v());
	    IfStmt toAdd1 = Jimple.v().newIfStmt(cond1,s);
	    // System.out.println(toAdd1);

	    NeExpr cond2 = Jimple.v().newNeExpr(s.getLeftOp(),s.getRightOp());
	    IfStmt toAdd2 = Jimple.v().newIfStmt(cond2,s);
	
	    // insert "if (op1 == null) goto <AssignStmt>"
	    units.insertBefore(toAdd1, s);

	    // insert "if (op1 != op2) goto <AssignStmt>"
	    units.insertBefore(toAdd2, s);

	    // insert silentStoreCounter increment
	    addCounterIncrement(units, s, counter, tmpLocal);
	    
	    // fix-up goto targets
	    toAdd1.setTarget(s);
	    toAdd2.setTarget(s);
	    return true;
	}
	return false;
    }

    protected void internalTransform(Body body, 
				     String phaseName,
				     Map options) {
	
	SootClass sClass = body.getMethod().getDeclaringClass();
        SootField storeCounter = null;
        SootField silentStoreCounter = null;
	boolean addedLocals = false;
        Local tmpRef = null, tmpLong = null;
	Chain units = body.getUnits();
	Local tmpLocal = Jimple.v().newLocal("tmp", LongType.v());
	body.getLocals().add(tmpLocal);
	boolean isMainMethod = body.getMethod().getSubSignature().equals(
				 "void main(java.lang.String[])");
	Iterator stmtIt = units.snapshotIterator();
	boolean initializedCounters = false;

	synchronized(this) {
	    
	    /* just check that there is a main method.
	    */
	    
	    if (!Scene.v().getMainClass().
		declaresMethod("void main(java.lang.String[])"))
		throw new RuntimeException(
		  "couldn't find main() in mainClass");

	    /* now add two field to the main class for counting stores 
	       and silent stores at runtime.
	    */
	    System.out.println(addedFieldsToMainClassAndLoadedPrintStream);
	    if (addedFieldsToMainClassAndLoadedPrintStream) {
		storeCounter = Scene.v().getMainClass().
		  getFieldByName("storeCounter");
                silentStoreCounter = Scene.v().getMainClass().
		  getFieldByName("silentStoreCounter");
	    }
	    else {
		/* add storeCounter and silentStoreCounter fields */
		storeCounter = new SootField(
		  "storeCounter", LongType.v(), Modifier.STATIC);
		Scene.v().getMainClass().addField(storeCounter);

		silentStoreCounter = new SootField(
                  "silentStoreCounter", LongType.v(), Modifier.STATIC);
		Scene.v().getMainClass().addField(silentStoreCounter);
		
		/* just in case, resolve the PrintStream SootClass */
		Scene.v().loadClassAndSupport("java.io.PrintStream");
		javaIoPrintStream = Scene.v().
		    getSootClass("java.io.PrintStream");
		addedFieldsToMainClassAndLoadedPrintStream = true;
	    }
	}
	    /*
	      Scene.v().getJimpleStmtPrinter().printStatementsInBody(body,
	      new PrintWriter(System.out), true, true);
	    */
	    
	
   	while(stmtIt.hasNext()) {
	    Stmt s = (Stmt) stmtIt.next();
	    //	    System.out.println(s);
	    if (isMainMethod && !initializedCounters) {
		units.insertBefore(Jimple.v().newAssignStmt(
	          Jimple.v().newStaticFieldRef(storeCounter),
	          LongConstant.v(0L)),s);
		units.insertBefore(Jimple.v().newAssignStmt(
		  Jimple.v().newStaticFieldRef(silentStoreCounter),
		  LongConstant.v(0L)),s);
		initializedCounters = true;
	    }
	    if (s instanceof AssignStmt) {
		addCounterIncrement(units, s, storeCounter, tmpLocal);
		addSilentStoreTest(units, (AssignStmt)s, silentStoreCounter,
				   tmpLocal);
	    }
	    if (s instanceof InvokeStmt) {
		InvokeExpr iexpr = 
		    (InvokeExpr)((InvokeStmt)s).getInvokeExpr();
		if (iexpr instanceof StaticInvokeExpr) {
		    SootMethod target = 
			((StaticInvokeExpr)iexpr).getMethod();
		    if (target.getSignature().equals(
		      "<java.lang.System: void exit(int)>")) {
			if (!addedLocals) {
			    tmpRef = addTmpRef(body); 
			    tmpLong = addTmpLong(body);
			    addedLocals = true;
			}
			addPrintCounter(units,
					s, storeCounter, tmpRef, tmpLong);
			addPrintCounter(units,
					s, silentStoreCounter, tmpRef, tmpLong);
		    }
		}
	    }
	    if (isMainMethod && (s instanceof ReturnStmt ||
				 s instanceof ReturnVoidStmt)) {
		if (!addedLocals) {
		    tmpRef = addTmpRef(body); 
		    tmpLong = addTmpLong(body);
		    addedLocals = true;
		}
		addPrintCounter(units, s, storeCounter, tmpRef, tmpLong);
		addPrintCounter(units, s, silentStoreCounter, tmpRef, tmpLong);
	    }
	}
	  
        /*
	Scene.v().getJimpleStmtPrinter().printStatementsInBody(body,
	  new PrintWriter(System.out), true, true);
	*/
    }
}