Mirror of the BLOAT repository
https://www.cs.purdue.edu/homes/hosking/bloat/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
985 lines
39 KiB
985 lines
39 KiB
/*
|
|
* Class: Peephole
|
|
* Version:
|
|
* Date:
|
|
*
|
|
* All files in the distribution of BLOAT (Bytecode Level Optimization and
|
|
* Analysis tool for Java(tm)) are Copyright 1997-2001 by the Purdue
|
|
* Research Foundation of Purdue University. All rights reserved.
|
|
*
|
|
* <p>
|
|
*
|
|
* Redistribution and use in source and binary forms are permitted
|
|
* provided that this entire copyright notice is duplicated in all
|
|
* such copies, and that any documentation, announcements, and other
|
|
* materials related to such distribution and use acknowledge that the
|
|
* software was developed at Purdue University, West Lafayette, IN by
|
|
* @author Antony Hosking
|
|
* @author David Whitlock
|
|
* @author Nathaniel Nystrom
|
|
* No charge may be made for copies, derivations, or distributions of
|
|
* this material without the express written consent of the copyright
|
|
* holder. Neither the name of the University nor the name of the
|
|
* author may be used to endorse or promote products derived from this
|
|
* material without specific prior written permission. THIS SOFTWARE
|
|
* IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
|
|
* WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES
|
|
* OF MERCHANTABILITY AND FITNESS FOR ANY PARTICULAR PURPOSE.
|
|
*
|
|
* <p>
|
|
*
|
|
* Port of the BLOAT to use the Jakata Apache project BCEL 5.2 was
|
|
* contributed by The Australian National University by
|
|
* @author Arrin Daley
|
|
* @author John N Zigman
|
|
*
|
|
* <p>
|
|
* Java is a trademark of Sun Microsystems, Inc.
|
|
*/
|
|
|
|
package edu.purdue.cs.bloat.trans;
|
|
|
|
import org.apache.bcel.generic.*;
|
|
|
|
import edu.purdue.cs.bloat.cfg.FlowGraph;
|
|
import edu.purdue.cs.bloat.optimize.MethodState;
|
|
import edu.purdue.cs.bloat.optimize.Optimization;
|
|
import edu.purdue.cs.bloat.util.Assert;
|
|
|
|
import java.util.*;
|
|
|
|
/**
|
|
* Performs some peephole optimizations such as loads and stores and removes
|
|
* unreachable instructions.
|
|
*/
|
|
|
|
public class Peephole implements Optimization {
|
|
|
|
public static boolean DEBUG = false;
|
|
|
|
public String traceMessage(String dateString) {
|
|
return null;
|
|
}
|
|
|
|
public String preDebugMessage() {
|
|
return null;
|
|
}
|
|
|
|
public String postDebugMessage() {
|
|
return null;
|
|
}
|
|
|
|
public void transform(MethodState state) {
|
|
this.transform(state.methodGen(), true);
|
|
}
|
|
|
|
/**
|
|
* Perform peephole optimizations on the bytecodes in a method. Peephole
|
|
* optimizations look at two consecutive instructions and try to perform
|
|
* some simple optimization. For instance, a push followed by a pop is
|
|
* uninteresting, so both of those instructions can be removed.
|
|
*
|
|
* <p>
|
|
*
|
|
* After the peephole optimizations are performed a final phase removes
|
|
* instructions that are not reachable. These instructions reside in basic
|
|
* blocks whose starting label is never jumped to.
|
|
*/
|
|
|
|
// Peephole can work on any bytecode sequence it does not have to be a
|
|
// result of calls
|
|
// to CodeGenerator. However, if Peephole will need to have labels denoting
|
|
// the start
|
|
// of basic blocks, if the code is not the result of output from
|
|
// CodeGenerator then labels
|
|
// will not be intact set "labels" to false if this is the case and they can
|
|
// be placed using
|
|
// FlowGraph.buildBLOATInstructionList(MethodGen) --Arrin
|
|
public void transform(MethodGen method, boolean labels) {
|
|
if (DEBUG) {
|
|
System.out.println("Peephole optimizing " + method);
|
|
}
|
|
|
|
// Map between labels and the instruction that they label
|
|
Map targets = new LinkedHashMap();
|
|
|
|
LinkedList jumps = new LinkedList(); // Jump instructions
|
|
|
|
Instruction next = null;
|
|
|
|
InstructionList code = method.getInstructionList();
|
|
// Do we need to build the labels are they already intact?
|
|
if (!labels)
|
|
FlowGraph.buildBLOATInstructionList(method);
|
|
|
|
InstructionHandle ih = null;
|
|
// Go backwards so we can eliminate redundant loads and stores
|
|
// in one pass. During the pass collect the locations of labels.
|
|
boolean canFilter = true;
|
|
CODE: for (ih = code.getEnd(); ih != code.getStart(); ih = ih.getPrev()) {
|
|
|
|
if (FlowGraph.label(ih)) {
|
|
targets.put(ih, ih.getInstruction());
|
|
}
|
|
|
|
// All items are Instructions now
|
|
Instruction inst = ih.getInstruction();
|
|
|
|
Filter peep = null;
|
|
|
|
// Have we seen a label that starts a block? (i.e. is a target)
|
|
boolean seenLabel = false;
|
|
|
|
if (inst instanceof GotoInstruction) {
|
|
// Look at the instructions following the goto. If an
|
|
// instruction follows and no label (that starts a block)
|
|
// has been seen, the instruction is dead and can be
|
|
// removed. If the target of the goto follows the goto
|
|
// instruction, the goto is useless and is removed.
|
|
|
|
InstructionHandle target = ((GotoInstruction) inst).getTarget();
|
|
|
|
for (InstructionHandle j = ih.getNext(); j != null; j = j
|
|
.getNext()) {
|
|
|
|
// Replace
|
|
// goto L
|
|
// L: inst
|
|
// with
|
|
// L: inst
|
|
//
|
|
if (FlowGraph.label(j)) {
|
|
// if (((Label) t).startsBlock()) {
|
|
// All labels start a block now
|
|
seenLabel = true;
|
|
|
|
if (target.equals(j)) {
|
|
InstructionHandle toDelete = ih;
|
|
ih = ih.getNext();
|
|
try {
|
|
code.delete(toDelete);
|
|
next = null;
|
|
} catch (TargetLostException tle) {
|
|
InstructionHandle[] losttargets = tle
|
|
.getTargets();
|
|
for (int i = 0; i < losttargets.length; i++) {
|
|
InstructionTargeter[] targeters = losttargets[i]
|
|
.getTargeters();
|
|
|
|
for (int k = 0; k < targeters.length; k++)
|
|
targeters[k].updateTarget(
|
|
losttargets[i], j);
|
|
}
|
|
// Redirect Lost targeters
|
|
}
|
|
continue CODE;
|
|
}
|
|
if (Peephole.DEBUG)
|
|
System.out.println("Not a target instruction : "
|
|
+ j.getInstruction());
|
|
// Now we want to look at the instruction
|
|
// continue;
|
|
}
|
|
|
|
// Replace
|
|
// goto L
|
|
// this is unreachable
|
|
// M: inst (M is a different label from L!)
|
|
// with
|
|
// goto L
|
|
// M: inst
|
|
//
|
|
// if (!FlowGraph.label(j)) {
|
|
if (seenLabel) {
|
|
break;
|
|
}
|
|
InstructionHandle j2 = j;
|
|
j = j.getPrev();
|
|
try {
|
|
code.delete(j2); // Delete an unreachable instruction
|
|
} catch (TargetLostException tle) {
|
|
System.out.println("Got a lost Target!!!!!!!");
|
|
// fail quitely
|
|
}
|
|
|
|
// }
|
|
}
|
|
}
|
|
|
|
if (inst instanceof GotoInstruction || inst instanceof Select
|
|
|| inst instanceof IfInstruction) {
|
|
jumps.add(ih);
|
|
}
|
|
|
|
// Performs some peephole optimizations using the filter
|
|
// method that returns an instance of the Filter class. The
|
|
// filter method looks at two consecutive instructions and
|
|
// determines whether or not something about them can be
|
|
// changed. For instance, if a push is followed by a pop,
|
|
// both instructions are useless and can be eliminated. The
|
|
// contents of the Filter object represents the effects of the
|
|
// peephole optimization.
|
|
if (next != null && canFilter) {
|
|
peep = filter(inst, next, method);
|
|
}
|
|
|
|
if (peep != null) {
|
|
if (Peephole.DEBUG) {
|
|
if (peep.replace.length == 0) {
|
|
System.out.println("eliminate " + ih.getInstruction()
|
|
+ "-" + ih.getNext().getInstruction());
|
|
|
|
} else {
|
|
System.out.println("replace " + ih.getInstruction()
|
|
+ "-" + ih.getNext().getInstruction());
|
|
System.out.println(" with");
|
|
for (int j = 0; j < peep.replace.length; j++) {
|
|
System.out.println(" " + peep.replace[j]);
|
|
}
|
|
}
|
|
}
|
|
InstructionHandle oldIh = ih;
|
|
ih = ih.getPrev();
|
|
InstructionHandle redirectTo = ih.getNext().getNext();
|
|
// if no Instruction is added redirect to after the deleted
|
|
// instructions
|
|
if (ih == null) {// we are at the start of the
|
|
// InstructionList
|
|
// Add instructions resulting from peephole optimizations
|
|
for (int j = peep.replace.length - 1; j >= 0; j--) {
|
|
if (peep.replace[j] instanceof BranchInstruction)
|
|
redirectTo = code
|
|
.insert((BranchInstruction) peep.replace[j]);
|
|
else
|
|
// UGH BCEL treats Branch instructions differently
|
|
redirectTo = code.insert(peep.replace[j]);
|
|
// break;
|
|
}
|
|
} else {
|
|
for (int j = peep.replace.length - 1; j >= 0; j--) {
|
|
if (peep.replace[j] instanceof BranchInstruction)
|
|
redirectTo = code.append(ih,
|
|
(BranchInstruction) peep.replace[j]);
|
|
else
|
|
// UGH BCEL treats Branch instructions differently
|
|
redirectTo = code.append(ih, peep.replace[j]);
|
|
}
|
|
}
|
|
try {
|
|
// Remove old instructions
|
|
code.delete(oldIh.getNext());
|
|
code.delete(oldIh);
|
|
} catch (TargetLostException tle) {
|
|
FlowGraph.setLabel(redirectTo); // reinstate as a label.
|
|
InstructionHandle[] losttargets = tle.getTargets();
|
|
for (int i = 0; i < losttargets.length; i++) {
|
|
InstructionTargeter[] targeters = losttargets[i]
|
|
.getTargeters();
|
|
|
|
for (int j = 0; j < targeters.length; j++)
|
|
targeters[j].updateTarget(losttargets[i],
|
|
redirectTo);
|
|
}
|
|
// Redirect Lost targeters
|
|
}
|
|
|
|
ih = ih.getNext();// This should be one of the added
|
|
// instructions if one was added.
|
|
if (ih != null && !FlowGraph.label(ih)) {
|
|
next = ih.getInstruction();
|
|
|
|
} else {
|
|
// No more instructions, or next thing is a label
|
|
next = null;
|
|
}
|
|
|
|
} else {
|
|
if (ih != null && !FlowGraph.label(ih)) {
|
|
next = ih.getInstruction();
|
|
} else {
|
|
next = null;
|
|
}
|
|
// Filter didn't find any peephole optimizations, skip to
|
|
// next pair of instructions.
|
|
}
|
|
|
|
}
|
|
|
|
if (DEBUG) {
|
|
System.out.println("Peephole optimizing removing GOTOs");
|
|
}
|
|
|
|
// Replace the target of jumps to gotos with the goto target.
|
|
// Replace gotos to unconditional jumps with the unconditional jump.
|
|
while (!jumps.isEmpty()) {
|
|
InstructionHandle iHandle = (InstructionHandle) jumps.removeFirst();
|
|
InstructionHandle target;
|
|
|
|
if ((iHandle.getInstruction() instanceof GotoInstruction)
|
|
|| (iHandle.getInstruction() instanceof IfInstruction)) {
|
|
BranchInstruction inst = (BranchInstruction) iHandle
|
|
.getInstruction();
|
|
target = inst.getTarget();
|
|
if (target != null) {
|
|
Instruction targetInst = target.getInstruction();
|
|
if (targetInst instanceof GotoInstruction
|
|
&& !(((GotoInstruction) targetInst).getTarget()
|
|
.equals(inst.getTarget()))) {
|
|
// IF THIS WASN'T TRUE WOULDN'T IT MEAN WE HAVE A GOTO
|
|
// DIRECTED TO JUMP TO ITSELF?
|
|
if (Peephole.DEBUG) {
|
|
System.out.println("replace " + inst);
|
|
}
|
|
|
|
inst.setTarget(((GotoInstruction) targetInst)
|
|
.getTarget());
|
|
|
|
if (Peephole.DEBUG) {
|
|
System.out.println(" with " + inst);
|
|
}
|
|
|
|
jumps.add(iHandle);
|
|
|
|
} else if ((inst instanceof GotoInstruction)
|
|
&& (targetInst instanceof Select ||
|
|
// targetInst instanceof ReturnInstruction ||
|
|
targetInst instanceof ATHROW)) {
|
|
|
|
if (Peephole.DEBUG) {
|
|
System.out.println("replace " + inst);
|
|
}
|
|
|
|
iHandle.setInstruction((BranchInstruction) targetInst
|
|
.copy());
|
|
// THIS MIGHT BE BAD copy() IS A SHALLOW COPY!!
|
|
|
|
if (Peephole.DEBUG) {
|
|
System.out.println(" with " + targetInst);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Remove unreachable code.
|
|
removeUnreachable(method, code);
|
|
|
|
Iterator iterhandles = method.getInstructionList().iterator();
|
|
while (iterhandles.hasNext()) {
|
|
ih = (InstructionHandle) iterhandles.next();
|
|
ih.removeAttribute("Label");
|
|
}
|
|
|
|
method.removeNOPs();
|
|
method.getInstructionList().setPositions();
|
|
method.setMaxStack();
|
|
method.setMaxLocals();
|
|
method.update();
|
|
|
|
if (Peephole.DEBUG) {
|
|
System.out.println("END PEEPHOLE--------------------------------");
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Iterate over the code in the method and determine which labels begin
|
|
* blocks that are reachable. The code in blocks that are not reachable is
|
|
* removed.
|
|
*/
|
|
// TODO: Currently, ALL ret targets are marked reachable from a
|
|
// single ret. Correct this by looking at the local variables.
|
|
private void removeUnreachable(MethodGen method, InstructionList code) {
|
|
// Maps Labels to their instruction position
|
|
Map labelPos = new LinkedHashMap();
|
|
|
|
// Collect all the ret targets.
|
|
Iterator iter = code.iterator();
|
|
int i = 0;
|
|
|
|
while (iter.hasNext()) {
|
|
InstructionHandle ce = (InstructionHandle) iter.next();
|
|
|
|
if (FlowGraph.label(ce)) {
|
|
labelPos.put(ce, new Integer(i));
|
|
}
|
|
|
|
i++;
|
|
}
|
|
|
|
// Visit the blocks depth-first.
|
|
|
|
// Stack of Labels that begin blocks that have been visited
|
|
Set visited = new LinkedHashSet();
|
|
|
|
// Stack of Labels that begin blocks that have not been visited
|
|
Stack stack = new Stack();
|
|
|
|
InstructionHandle label; // Current label
|
|
|
|
if (code.getLength() > 0) {
|
|
// Start with the label of the first block
|
|
label = (InstructionHandle) code.getStart();
|
|
visited.add(label);
|
|
stack.push(label);
|
|
}
|
|
|
|
CodeExceptionGen[] excptns = method.getExceptionHandlers();
|
|
|
|
for (i = 0; i < excptns.length; i++) {
|
|
// All exception handlers are considered to be live
|
|
visited.add(excptns[i].getHandlerPC());
|
|
stack.push(excptns[i].getHandlerPC());
|
|
}
|
|
|
|
while (!stack.isEmpty()) {
|
|
label = (InstructionHandle) stack.pop();
|
|
|
|
Integer labelIndex = (Integer) labelPos.get(label);
|
|
Assert.isTrue(labelIndex != null, "Index of label_"
|
|
+ label.getPosition() + " not found");
|
|
|
|
InstructionHandle blockIter = label;
|
|
|
|
while (blockIter != null && blockIter.getNext() != null) {
|
|
// Iterate over the code in the block. If we encounter
|
|
// instructions that change execution (i.e. go to another
|
|
// block), add the Label of the target of the jump to the
|
|
// stack if it is not already present.
|
|
|
|
blockIter = blockIter.getNext();
|
|
Instruction inst = blockIter.getInstruction();
|
|
|
|
// BCEL - BLOAT means jumps can also be Labels.
|
|
if (FlowGraph.label(blockIter)) {
|
|
label = blockIter;
|
|
visited.add(label);
|
|
}
|
|
|
|
if (inst instanceof ReturnInstruction || inst instanceof ATHROW) {
|
|
// We've reached the end of the block, but we don't know
|
|
// which block will be executed next.
|
|
break;
|
|
|
|
} else if (inst instanceof IfInstruction
|
|
|| inst instanceof JsrInstruction) {
|
|
// We've reached the end of the block, add the Label of
|
|
// the next block to be executed to the list. It's a
|
|
// conditional jump, so don't break. The rest of the
|
|
// code in the block is not necessarily dead.
|
|
|
|
label = ((BranchInstruction) inst).getTarget();
|
|
|
|
if (!visited.contains(label)) {
|
|
visited.add(label);
|
|
stack.push(label);
|
|
}
|
|
|
|
// Fall through.
|
|
|
|
} else if (inst instanceof GotoInstruction) {
|
|
// Add next block to work list.
|
|
|
|
label = ((GotoInstruction) inst).getTarget();
|
|
|
|
if (!visited.contains(label)) {
|
|
visited.add(label);
|
|
stack.push(label);
|
|
}
|
|
|
|
break;
|
|
|
|
} else if (inst instanceof RET) {
|
|
// The ret targets were handled by the jsr.
|
|
break;
|
|
|
|
} else if (inst instanceof Select) {
|
|
// A switch. Add all possible targets of the switch to
|
|
// the worklist.
|
|
|
|
Select sw = (Select) inst;
|
|
|
|
label = sw.getTarget();
|
|
if (!visited.contains(label)) {
|
|
visited.add(label);
|
|
stack.push(label);
|
|
}
|
|
|
|
InstructionHandle[] targets = sw.getTargets();
|
|
|
|
for (int j = 0; j < targets.length; j++) {
|
|
label = targets[j];
|
|
|
|
if (!visited.contains(label)) {
|
|
visited.add(label);
|
|
stack.push(label);
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
|
|
}
|
|
}
|
|
if (DEBUG) {
|
|
System.out.println("Done finding unreachable instructions");
|
|
}
|
|
|
|
boolean reachable = false;
|
|
|
|
iter = code.iterator();
|
|
|
|
// Remove unreachable instructions
|
|
while (iter.hasNext()) {
|
|
InstructionHandle ce = (InstructionHandle) iter.next();
|
|
|
|
if (FlowGraph.label(ce)) {
|
|
reachable = visited.contains(ce);
|
|
// Don't remove unreachable labels, only instructions.
|
|
|
|
}
|
|
if (!reachable) {
|
|
if (Peephole.DEBUG) {
|
|
System.out.println("Removing unreachable " + ce);
|
|
}
|
|
try {
|
|
code.delete(ce);
|
|
} catch (TargetLostException lte) {
|
|
// do nothing if this is dead code there shouldn't be a
|
|
// targeter.
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filter represents a set of instructions that result from a peephole
|
|
* optimizations. For instance, when uninteresting instructions are removed,
|
|
* a Filter object with an empty "replace" array will be returned by the
|
|
* below filter method.
|
|
*/
|
|
static class Filter {
|
|
Instruction[] replace;
|
|
|
|
boolean[] labels;
|
|
|
|
Filter() {
|
|
this.replace = new Instruction[0];
|
|
}
|
|
|
|
Filter(Instruction replace) {
|
|
this.replace = new Instruction[] { replace };
|
|
}
|
|
|
|
Filter(Instruction replace1, Instruction replace2) {
|
|
this.replace = new Instruction[] { replace1, replace2 };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Filter a pair of instructions. That is, do a peephole optimization on two
|
|
* consecutive instructions. For instance, if a push is followed by a pop,
|
|
* both instructions can be eliminated. The <tt>Filter</tt> object that is
|
|
* returned specifies what instruction(s), if any, should replace the two
|
|
* instructions that are the parameters to this method.
|
|
*
|
|
* @param first
|
|
* The first instruction.
|
|
* @param second
|
|
* The second instruction.
|
|
* @return A list of instructions to replace the two instructions with, or
|
|
* null, if the instructions should be left as is.
|
|
*/
|
|
private Filter filter(Instruction first, Instruction second,
|
|
MethodGen method) {
|
|
// switch (second.opcodeClass()) {
|
|
|
|
// swap means nothing if it's after a dup.
|
|
// (goodbye means nothing when it's all for show
|
|
// so stop pretending you've somewhere else to go.)
|
|
|
|
// case opcx_swap:
|
|
if (second instanceof SWAP) {
|
|
// Elminate swap-swap
|
|
if (first instanceof SWAP)
|
|
return new Filter();
|
|
// swap means nothing if it's after a dup.
|
|
// (goodbye means nothing when it's all for show
|
|
// so stop pretending you've somewhere else to go.)
|
|
if (first instanceof DUP) {
|
|
return new Filter(first);
|
|
}
|
|
} else if (second instanceof POP) {// Eliminate push-pop.
|
|
// Eliminate push-pop.
|
|
|
|
// switch (first.opcodeClass()) {
|
|
if (first instanceof LDC) {
|
|
LDC f = (LDC) first;
|
|
// Make sure things being popped off is not wide (we're
|
|
// dealing with a pop not a pop2).
|
|
Assert.isTrue(!(f.getType(method.getConstantPool())
|
|
.equals(Type.LONG))
|
|
&& !(f.getType(method.getConstantPool())
|
|
.equals(Type.DOUBLE)),
|
|
"Cannot pop a 2-word operand");
|
|
return new Filter();
|
|
} else if ((first instanceof ILOAD) || (first instanceof FLOAD)
|
|
|| (first instanceof ALOAD) || (first instanceof DUP)) {
|
|
// Eliminate the load and the pop.
|
|
return new Filter();
|
|
} else if (first instanceof DUP_X1) {
|
|
// Replace dup_x1-pop with swap
|
|
// (As if this is really likely to happen ;) <-- Nate made a
|
|
// joke!
|
|
System.out.println("HERE0 inserting SWAP");
|
|
return new Filter(new SWAP());
|
|
}
|
|
} else if (second instanceof POP2) {
|
|
if (first instanceof LDC) {
|
|
LDC f = (LDC) first;
|
|
Assert.isTrue((f.getType(method.getConstantPool())
|
|
.equals(Type.LONG))
|
|
|| (f.getType(method.getConstantPool())
|
|
.equals(Type.DOUBLE)),
|
|
"Cannot pop2 a 1-word operand");
|
|
return new Filter();
|
|
} else if ((first instanceof LLOAD) || (first instanceof DLOAD)
|
|
|| (first instanceof DUP2)) {
|
|
// Eliminate push and pop
|
|
return new Filter();
|
|
}
|
|
} else if (second instanceof ISTORE) {
|
|
StoreInstruction secnd = (StoreInstruction) second;
|
|
// Eliminate load-store to same location.
|
|
if (first instanceof ILOAD) {
|
|
LoadInstruction frst = (LoadInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter();
|
|
}
|
|
}
|
|
} else if (second instanceof FSTORE) {
|
|
StoreInstruction secnd = (StoreInstruction) second;
|
|
if (first instanceof FLOAD) {
|
|
LoadInstruction frst = (LoadInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter();
|
|
}
|
|
}
|
|
} else if (second instanceof ASTORE) {
|
|
StoreInstruction secnd = (StoreInstruction) second;
|
|
if (first instanceof ALOAD) {
|
|
LoadInstruction frst = (LoadInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter();
|
|
}
|
|
}
|
|
} else if (second instanceof LSTORE) {
|
|
StoreInstruction secnd = (StoreInstruction) second;
|
|
if (first instanceof LLOAD) {
|
|
LoadInstruction frst = (LoadInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter();
|
|
}
|
|
}
|
|
} else if (second instanceof DSTORE) {
|
|
StoreInstruction secnd = (StoreInstruction) second;
|
|
if (first instanceof DLOAD) {
|
|
LoadInstruction frst = (LoadInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter();
|
|
}
|
|
}
|
|
} else if (second instanceof ReturnInstruction) {
|
|
// THIS APPLIES FOR RETURN TOO RIGHT?
|
|
// Replace store-return with return. Remember that upon return
|
|
// all local variables revert to their pre-call values, so any
|
|
// stores are destroyed.
|
|
if (first instanceof StoreInstruction) {
|
|
return new Filter(second);
|
|
}
|
|
} else if (second instanceof IADD) {
|
|
// Replace ineg-iadd with isub
|
|
if (first instanceof INEG) {
|
|
return new Filter(new ISUB());
|
|
}
|
|
} else if (second instanceof ISUB) {
|
|
// Replace ineg-isub with iadd
|
|
if (first instanceof INEG) {
|
|
return new Filter(new IADD());
|
|
}
|
|
} else if (second instanceof LADD) {
|
|
// Replace lneg-ladd with lsub
|
|
if (first instanceof LNEG) {
|
|
return new Filter(new LSUB());
|
|
}
|
|
} else if (second instanceof LSUB) {
|
|
// Replace lneg-lsub with ladd
|
|
if (first instanceof LNEG) {
|
|
return new Filter(new LADD());
|
|
}
|
|
} else if (second instanceof IF_ICMPEQ) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc 0-if_icmpeq with ifeq
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
Object op = frst.getValue(method.getConstantPool());
|
|
if (op instanceof Integer) {
|
|
if (((Integer) op).intValue() == 0) {
|
|
return new Filter(new IFEQ(secnd.getTarget()));
|
|
}
|
|
}
|
|
}
|
|
} else if (second instanceof IF_ICMPNE) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc 0-if_icmpne with ifne
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
Object op = frst.getValue(method.getConstantPool());
|
|
if (op instanceof Integer) {
|
|
if (((Integer) op).intValue() == 0) {
|
|
return new Filter(new IFNE(secnd.getTarget()));
|
|
}
|
|
}
|
|
}
|
|
} else if (second instanceof IF_ICMPLT) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc 0-if_icmplt with iflt
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
Object op = frst.getValue(method.getConstantPool());
|
|
if (op instanceof Integer) {
|
|
if (((Integer) op).intValue() == 0) {
|
|
return new Filter(new IFLT(secnd.getTarget()));
|
|
}
|
|
}
|
|
}
|
|
} else if (second instanceof IF_ICMPGE) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc 0-if_icmpge with ifge
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
Object op = frst.getValue(method.getConstantPool());
|
|
if (op instanceof Integer) {
|
|
if (((Integer) op).intValue() == 0) {
|
|
return new Filter(new IFGE(secnd.getTarget()));
|
|
}
|
|
}
|
|
}
|
|
} else if (second instanceof IF_ICMPGT) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc 0-if_icmpgt with ifgt
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
Object op = frst.getValue(method.getConstantPool());
|
|
if (op instanceof Integer) {
|
|
if (((Integer) op).intValue() == 0) {
|
|
return new Filter(new IFGT(secnd.getTarget()));
|
|
}
|
|
}
|
|
}
|
|
} else if (second instanceof IF_ICMPLE) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc 0-if_icmple with ifle
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
Object op = frst.getValue(method.getConstantPool());
|
|
if (op instanceof Integer) {
|
|
if (((Integer) op).intValue() == 0) {
|
|
return new Filter(new IFLE(secnd.getTarget()));
|
|
}
|
|
}
|
|
}
|
|
} else if (second instanceof IF_ACMPEQ) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc null-if_acmpeq with ifnull
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
if (frst.getValue(method.getConstantPool()) == null) {
|
|
return new Filter(new IFNULL(secnd.getTarget()));
|
|
}
|
|
}
|
|
} else if (second instanceof IF_ACMPNE) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc null-if_acmpne with ifnonnull
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
if (frst.getValue(method.getConstantPool()) == null) {
|
|
return new Filter(new IFNONNULL(secnd.getTarget()));
|
|
}
|
|
}
|
|
} else if (second instanceof IFEQ) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc 0-ifeq with goto and eliminate ldc !0-ifeq
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
Object op = frst.getValue(method.getConstantPool());
|
|
if (op instanceof Integer) {
|
|
if (((Integer) op).intValue() == 0) {
|
|
return new Filter(new GOTO(secnd.getTarget()));
|
|
} else {
|
|
return new Filter();
|
|
}
|
|
}
|
|
}
|
|
} else if (second instanceof IFNE) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc !0-ifne with goto and eliminate ldc 0-ifne
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
Object op = frst.getValue(method.getConstantPool());
|
|
if (op instanceof Integer) {
|
|
if (((Integer) op).intValue() != 0) {
|
|
return new Filter(new GOTO(secnd.getTarget()));
|
|
} else {
|
|
return new Filter();
|
|
}
|
|
}
|
|
}
|
|
} else if (second instanceof IFLT) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc <0-iflt with goto and eliminate ldc >=0-iflt
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
Object op = frst.getValue(method.getConstantPool());
|
|
if (op instanceof Integer) {
|
|
if (((Integer) op).intValue() < 0) {
|
|
return new Filter(new GOTO(secnd.getTarget()));
|
|
} else {
|
|
return new Filter();
|
|
}
|
|
}
|
|
}
|
|
} else if (second instanceof IFGE) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc >=0-ifge with goto and eliminate ldc <0-ifge
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
Object op = frst.getValue(method.getConstantPool());
|
|
if (op instanceof Integer) {
|
|
if (((Integer) op).intValue() >= 0) {
|
|
return new Filter(new GOTO(secnd.getTarget()));
|
|
} else {
|
|
return new Filter();
|
|
}
|
|
}
|
|
}
|
|
} else if (second instanceof IFGT) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc >0-ifgt with goto and eliminate ldc <=0-ifgt
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
Object op = frst.getValue(method.getConstantPool());
|
|
if (op instanceof Integer) {
|
|
if (((Integer) op).intValue() > 0) {
|
|
return new Filter(new GOTO(secnd.getTarget()));
|
|
} else {
|
|
return new Filter();
|
|
}
|
|
}
|
|
}
|
|
} else if (second instanceof IFLE) {
|
|
BranchInstruction secnd = (BranchInstruction) second;
|
|
// Replace ldc <=0-ifle with goto and eliminate ldc >0-ifle
|
|
if (first instanceof LDC) {
|
|
LDC frst = (LDC) first;
|
|
Object op = frst.getValue(method.getConstantPool());
|
|
if (op instanceof Integer) {
|
|
if (((Integer) op).intValue() <= 0) {
|
|
return new Filter(new GOTO(secnd.getTarget()));
|
|
} else {
|
|
return new Filter();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (second instanceof StoreInstruction) {
|
|
StoreInstruction secnd = (StoreInstruction) second;
|
|
// Replace store-store to same location with pop-store.
|
|
if (first instanceof StoreInstruction) {
|
|
StoreInstruction frst = (StoreInstruction) first;
|
|
if ((frst instanceof LSTORE) || (frst instanceof DSTORE)) {
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter(new POP2(), first);
|
|
}
|
|
} else {
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter(new POP(), first);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Replace store-load with dup-store.
|
|
// Replace load-load with load-dup.
|
|
if (second instanceof ILOAD) {
|
|
LoadInstruction secnd = (LoadInstruction) second;
|
|
if (first instanceof ISTORE) {
|
|
StoreInstruction frst = (StoreInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter(new DUP(), first);
|
|
}
|
|
}
|
|
if (first instanceof ILOAD) {
|
|
LoadInstruction frst = (LoadInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter(first, new DUP());
|
|
}
|
|
}
|
|
} else if (second instanceof FLOAD) {
|
|
LoadInstruction secnd = (LoadInstruction) second;
|
|
if (first instanceof FSTORE) {
|
|
StoreInstruction frst = (StoreInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter(new DUP(), first);
|
|
}
|
|
}
|
|
if (first instanceof FLOAD) {
|
|
LoadInstruction frst = (LoadInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter(first, new DUP());
|
|
}
|
|
}
|
|
} else if (second instanceof ALOAD) {
|
|
LoadInstruction secnd = (LoadInstruction) second;
|
|
if (first instanceof ASTORE) {
|
|
StoreInstruction frst = (StoreInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter(new DUP(), first);
|
|
}
|
|
}
|
|
if (first instanceof ALOAD) {
|
|
LoadInstruction frst = (LoadInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter(first, new DUP());
|
|
}
|
|
}
|
|
} else if (second instanceof LLOAD) {
|
|
LoadInstruction secnd = (LoadInstruction) second;
|
|
if (first instanceof LSTORE) {
|
|
StoreInstruction frst = (StoreInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter(new DUP2(), first);
|
|
}
|
|
}
|
|
if (first instanceof LLOAD) {
|
|
LoadInstruction frst = (LoadInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter(first, new DUP2());
|
|
}
|
|
}
|
|
} else if (second instanceof DLOAD) {
|
|
LoadInstruction secnd = (LoadInstruction) second;
|
|
if (first instanceof DSTORE) {
|
|
StoreInstruction frst = (StoreInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter(new DUP2(), first);
|
|
}
|
|
}
|
|
if (first instanceof DLOAD) {
|
|
LoadInstruction frst = (LoadInstruction) first;
|
|
if (frst.getIndex() == secnd.getIndex()) {
|
|
return new Filter(first, new DUP2());
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
|