CS243 Homework 4

Finding Redundant Null Checks

Due: 11:00 AM, Wednesday, February 27th, 2008

Introduction

When generating quads out of Java bytecodes, safety checks are explicitly inserted into the control flow graph. In particular, every register is NULL_CHECKed before it is deferenced. These safety checks are necessary to ensure memory safety, but cause substantial runtime overhead. In this assignment, you will design sound optimizations to eliminate redundant checks and to optimize the program in general.

Copy /usr/class/cs243/optimize/optimize.tar.gz from a Stanford machine to your local machine. The optimize package contains a monotone dataflow framework, several client analyses, and additional utilies that may be useful. You may only modify classes in the optimize.* package except for optimize.OptimizeHarness. In addition, you must adhere to the interfaces of the methods optimize.Optimize.optimize and optimize.FindRedundantNullChecks.main as specified in the comments preceding each method declaration.

Assignment

Write an analysis to find all redundant NULL_CHECKs. A NULL_CHECK on register x is redundant at point p if x successfully passed a NULL_CHECK along all possible paths to p. For example, in the following code, your analysis must find quad 5 to be redundant but does not need to find any other quad to be redundant.


1   MOVE T1 String, T0 String
2   NULL_CHECK T-1 <g>, T1 String
3   MOVE T2 String, T1 String
4   NULL_CHECK T-1 <g>, T0 String
5   NULL_CHECK T-1 <g>, T1 String
6   NULL_CHECK T-1 <g>, T2 String

In other words, your analysis needs to find that a NULL_CHECK is redundant on a register only if that particular register was NULL_CHECK'ed along all possible paths to that NULL_CHECK. The analysis does not have to reason about copies of values to or from other previously or subsequently NULL_CHECK'ed registers.

The optimize.FindRedundantNullChecks.main(String[]) method takes an array of names of classes that should be analyzed for redundant null checks. Fill in the optimize.FindRedundantNullChecks.main(String[]) method so that it prints exactly one line for each method that contains the method name and a superset of the quad ids of redundant NULL_CHECKs. For example:

elaine:~/optimize$ ./bin/parun optimize.FindRedundantNullChecks optimize.test.SomeTest
main 4 17 19
sample 5
<init>

means that NULL_CHECKs with quad ids 4, 17, and 19 are redundant in main, quad ids 5 are redundant in sample, and no quads are redundant in <init>.

The optimize.test package contains two test classes named optimize.test.NullTest and optimize.test.TowersOfHanoi. The outputs that should be generated by running optimize.FindRedundantNullChecks.main(String[]) over these two classes are in src/optimize/test/NullTest.basic.out and src/optimize/test/TowersOfHanoi.basic.out.

Extra Credit

Perform any other sound optimization that speeds up the optimize.test.TowersOfHanoi program. The extra credit points awarded will range from 0 to 100. The number of points will depend on the number of quads executed by the optimized program, and will be applied after all grades are curved. If you work in a group of two, the same extra credit score is assigned to both members. All optimizations must be sound! For example, if you remove even one necessary null or bounds check, or falsely copy a constant, you will receive no extra credit.

Your extra credit optimizations must transform the code so that the grading script can interpret the optimized program to determine the number of quads actually executed. The two easiest transforms are the removal and addition of quads using the QuadIterator's remove() and add(Object o) methods which will remove the most recently returned quad or insert a quad after it, respectively. To change the values of Operands, the Operator class contains static methods to set the appropriate argument. For example, Move has methods setDest and setSrc. To modify the ControlFlowGraph, use ControlFlowGraph.createBasicBlock to construct a BasicBlock and use the add methods in BasicBlock to modify the lists of quads. See the joeq javadocs for details.

The optimize.OptimizeHarness.main(String[]) method takes an list of names of classes that should be optimized, a run class that contains a static main(String[]) method, and a list of run parameters to be passed to the main method. For example:

elaine:~/optimize$ ./bin/parun optimize.OptimizeHarness --optimize optimize.test.TowersOfHanoi --run-main optimize.test.TowersOfHanoi --run-param 10
Result of interpretation: Returned: null (null checks: 37162 quad count: 129224)

applies your optimizations to optimize.test.TowersOfHanoi, and then interprets optimize.test.TowersOfHanoi with parameter 10. The interpreter prints out the number of quads executed.

The optimize.OptimizeHarness.main(String[]) method invokes the optimize.Optimize.optimize(List<String>) method which should load the classes to be optimized and apply the control flow graph transformations. The transformed control flow graphs should automatically be stored by joeq.Compiler.Quad.CodeCache. Read joeq.Compiler.Quad.CodeCache and joeq.Main.Helper carefully to understand how control flow graphs are cached. The optimize.OptimizeHarness.main(String[]) method then interprets the run class with respect to the list of run parameters using the CodeCacheed control flow graphs.

Fill in the optimize.Optimize.optimize(List<String>) method so that it applies your optimizations to the classes named by the list of strings parameter.

Describe the design of your extra credit optimizations in the design.txt file in the root directory.

Submission

Tarball your entire optimize directory and copy it to elaine:/usr/class/cs243/area/students/<sunetid>/hw4, where <sunetid> is your SUNetID. For example:

elaine:~$ tar cvf optimize.tar optimize
elaine:~$ gzip optimize.tar
elaine:~$ cp optimize.tar.gz /usr/class/cs243/area/students/<sunetid>/hw4
Each person must submit a tarball in their own directory even if they worked in a group.

Frequently Asked Questions

Q: Joeq inserts a NULL_CHECK on the value returned from the new operator. Is it safe to eliminate this NULL_CHECK?

A: Yes, it is safe to eliminate this NULL_CHECK because new will always either return a non-null value or throw an exception.