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.
 
 
 
 
bloat/src/EDU/purdue/cs/bloat/inline/StackHeightCounter.java

726 lines
16 KiB

/**
* 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.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
package EDU.purdue.cs.bloat.inline;
import java.util.*;
import EDU.purdue.cs.bloat.editor.*;
/**
* Used to keep track of the height of the stack. As instructions are visited,
* the height of the stack is adjusted accordingly.
*/
public class StackHeightCounter extends InstructionAdapter {
public static boolean DEBUG = false;
private int height; // Current stack height
private HashMap labelHeights; // Maps labels to their heights as Integers
private MethodEditor method; // Method whose height we're computing
Set tryCatches; // TryCatches active at current instruction
private static void db(final String s) {
if (StackHeightCounter.DEBUG) {
System.out.println(s);
}
}
public StackHeightCounter(final MethodEditor method) {
this.method = method;
this.height = 0;
this.labelHeights = new HashMap();
this.tryCatches = new HashSet();
}
/**
* Returns the current height of the stack.
*/
public int height() {
return (this.height);
}
/**
* Handles a Label. Special provisions must be made for labels that catch
* exceptions.
*/
public void handle(final Label label) {
final Integer labelHeight = (Integer) labelHeights.get(label);
if (labelHeight != null) {
height = labelHeight.intValue();
}
// If this label begins an exception handler, then start it off
// with a new stack with one element (the exception object) on it.
final Iterator tryCatches = method.tryCatches().iterator();
while (tryCatches.hasNext()) {
final TryCatch tc = (TryCatch) tryCatches.next();
if (tc.handler().equals(label)) {
label.setStartsBlock(true);
height = 1;
break;
}
if (tc.start().equals(label)) {
// If this block starts a protected region make note of the
// TryCatch block
this.tryCatches.add(tc);
}
if (tc.end().equals(label)) {
// If this block ends a protected region, remove it from the
// tryCatches list
this.tryCatches.remove(tc);
}
}
}
/**
* Handles an instruction. Special provisions must be made to handle jumps,
* switches, throws, and returns.
*/
public void handle(final Instruction inst) {
inst.visit(this);
if (inst.isJump()) {
final Label target = (Label) inst.operand();
target.setStartsBlock(true);
final Integer targetHeight = (Integer) labelHeights.get(target);
if (targetHeight != null) {
if (targetHeight.intValue() != height) {
// Make sure stack heights match
StackHeightCounter.db("Stack height mismatch ("
+ targetHeight.intValue() + " != " + height
+ ") at " + inst);
}
} else {
labelHeights.put(target, new Integer(height));
}
} else if (inst.isSwitch()) {
// Propagate height to all targets
final Switch sw = (Switch) inst.operand();
final Label defaultTarget = sw.defaultTarget();
defaultTarget.setStartsBlock(true);
final Integer dTargetHeight = (Integer) labelHeights
.get(defaultTarget);
if (dTargetHeight != null) {
if (dTargetHeight.intValue() != height) {
// Make sure stack heights match
StackHeightCounter.db("Stack height mismatch ("
+ dTargetHeight.intValue() + " != " + height
+ ") at " + inst);
}
} else {
labelHeights.put(defaultTarget, new Integer(height));
}
final Label[] targets = sw.targets();
for (int t = 0; t < targets.length; t++) {
final Label target = targets[t];
target.setStartsBlock(true);
final Integer targetHeight = (Integer) labelHeights.get(target);
if (targetHeight != null) {
if (targetHeight.intValue() != height) {
// Make sure stack heights match
StackHeightCounter.db("Stack height mismatch ("
+ targetHeight.intValue() + " != " + height
+ ") at " + inst);
}
} else {
labelHeights.put(target, new Integer(height));
}
}
} else if (inst.isJsr()) {
// We have to account for the return address being pushed on the
// stack. Let's ignore the fact that someday in the future
// subroutines may push stuff on the stack. M'kay?
final Label subroutine = (Label) inst.operand();
subroutine.setStartsBlock(true);
final Integer subHeight = (Integer) labelHeights.get(subroutine);
if (subHeight != null) {
if (subHeight.intValue() != height + 1) {
StackHeightCounter
.db("Stack height mismatch at subroutine ("
+ subHeight.intValue() + " != "
+ (height + 1) + ") at " + inst);
}
} else {
labelHeights.put(subroutine, new Integer(height + 1));
}
} else if (inst.isThrow() || inst.isReturn()) {
// Clear the stack
height = 0;
}
}
/**
* Simulates the effect of "backing up" over an instruction.
*/
public void unhandle(final Instruction inst) {
// Temporarily negate the stack height, perform the normal handle,
// and then negate the stack height again.
this.height = -this.height;
this.handle(inst);
this.height = -this.height;
}
/**
* Returns the set of <tt>TryCatch</tt> objects for the protected region
* that the current instruction may be in.
*/
public Set tryCatches() {
return (this.tryCatches);
}
public void visit_ldc(final Instruction inst) {
final Object operand = inst.operand();
if ((operand instanceof Long) || (operand instanceof Double)) {
height += 2;
} else {
height += 1;
}
}
public void visit_iload(final Instruction inst) {
height += 1;
}
public void visit_lload(final Instruction inst) {
height += 2;
}
public void visit_fload(final Instruction inst) {
height += 1;
}
public void visit_dload(final Instruction inst) {
height += 2;
}
public void visit_aload(final Instruction inst) {
height += 1;
}
public void visit_iaload(final Instruction inst) {
height -= 1;
}
public void visit_laload(final Instruction inst) {
height -= 0;
}
public void visit_faload(final Instruction inst) {
height -= 1;
}
public void visit_daload(final Instruction inst) {
height -= 0;
}
public void visit_aaload(final Instruction inst) {
height -= 1;
}
public void visit_baload(final Instruction inst) {
height -= 1;
}
public void visit_caload(final Instruction inst) {
height -= 1;
}
public void visit_saload(final Instruction inst) {
height -= 1;
}
public void visit_istore(final Instruction inst) {
height -= 1;
}
public void visit_lstore(final Instruction inst) {
height -= 2;
}
public void visit_fstore(final Instruction inst) {
height -= 1;
}
public void visit_dstore(final Instruction inst) {
height -= 2;
}
public void visit_astore(final Instruction inst) {
height -= 1;
}
public void visit_iastore(final Instruction inst) {
height -= 3;
}
public void visit_lastore(final Instruction inst) {
height -= 4;
}
public void visit_fastore(final Instruction inst) {
height -= 3;
}
public void visit_dastore(final Instruction inst) {
height -= 4;
}
public void visit_aastore(final Instruction inst) {
height -= 3;
}
public void visit_bastore(final Instruction inst) {
height -= 3;
}
public void visit_castore(final Instruction inst) {
height -= 3;
}
public void visit_sastore(final Instruction inst) {
height -= 3;
}
public void visit_pop(final Instruction inst) {
height -= 1;
}
public void visit_pop2(final Instruction inst) {
height -= 2;
}
public void visit_dup(final Instruction inst) {
height += 1;
}
public void visit_dup_x1(final Instruction inst) {
height += 1;
}
public void visit_dup_x2(final Instruction inst) {
height += 1;
}
public void visit_dup2(final Instruction inst) {
height += 2;
}
public void visit_dup2_x1(final Instruction inst) {
height += 2;
}
public void visit_dup2_x2(final Instruction inst) {
height += 2;
}
public void visit_iadd(final Instruction inst) {
height -= 1;
}
public void visit_ladd(final Instruction inst) {
height -= 2;
}
public void visit_fadd(final Instruction inst) {
height -= 1;
}
public void visit_dadd(final Instruction inst) {
height -= 2;
}
public void visit_isub(final Instruction inst) {
height -= 1;
}
public void visit_lsub(final Instruction inst) {
height -= 2;
}
public void visit_fsub(final Instruction inst) {
height -= 1;
}
public void visit_dsub(final Instruction inst) {
height -= 2;
}
public void visit_imul(final Instruction inst) {
height -= 1;
}
public void visit_lmul(final Instruction inst) {
height -= 2;
}
public void visit_fmul(final Instruction inst) {
height -= 1;
}
public void visit_dmul(final Instruction inst) {
height -= 2;
}
public void visit_idiv(final Instruction inst) {
height -= 1;
}
public void visit_ldiv(final Instruction inst) {
height -= 2;
}
public void visit_fdiv(final Instruction inst) {
height -= 1;
}
public void visit_ddiv(final Instruction inst) {
height -= 2;
}
public void visit_irem(final Instruction inst) {
height -= 1;
}
public void visit_lrem(final Instruction inst) {
height -= 2;
}
public void visit_frem(final Instruction inst) {
height -= 1;
}
public void visit_drem(final Instruction inst) {
height -= 2;
}
public void visit_ishl(final Instruction inst) {
height -= 1;
}
public void visit_lshl(final Instruction inst) {
height -= 1;
}
public void visit_ishr(final Instruction inst) {
height -= 1;
}
public void visit_lshr(final Instruction inst) {
height -= 1;
}
public void visit_iushr(final Instruction inst) {
height -= 1;
}
public void visit_lushr(final Instruction inst) {
// Yes, it's only -1. The long and the int index are popped off
// and the shifted value is pushed. Net loss of 1.
height -= 1;
}
public void visit_iand(final Instruction inst) {
height -= 1;
}
public void visit_land(final Instruction inst) {
height -= 2;
}
public void visit_ior(final Instruction inst) {
height -= 1;
}
public void visit_lor(final Instruction inst) {
height -= 2;
}
public void visit_ixor(final Instruction inst) {
height -= 1;
}
public void visit_lxor(final Instruction inst) {
height -= 2;
}
public void visit_i2l(final Instruction inst) {
height += 1;
}
public void visit_i2d(final Instruction inst) {
height += 1;
}
public void visit_l2i(final Instruction inst) {
height -= 1;
}
public void visit_l2f(final Instruction inst) {
height -= 1;
}
public void visit_f2l(final Instruction inst) {
height += 1;
}
public void visit_f2d(final Instruction inst) {
height += 1;
}
public void visit_d2i(final Instruction inst) {
height -= 1;
}
public void visit_d2f(final Instruction inst) {
height -= 1;
}
public void visit_lcmp(final Instruction inst) {
height -= 3;
}
public void visit_fcmpl(final Instruction inst) {
height -= 1;
}
public void visit_fcmpg(final Instruction inst) {
height -= 1;
}
public void visit_dcmpl(final Instruction inst) {
height -= 3;
}
public void visit_dcmpg(final Instruction inst) {
height -= 3;
}
public void visit_ifeq(final Instruction inst) {
height -= 1;
}
public void visit_ifne(final Instruction inst) {
height -= 1;
}
public void visit_iflt(final Instruction inst) {
height -= 1;
}
public void visit_ifge(final Instruction inst) {
height -= 1;
}
public void visit_ifgt(final Instruction inst) {
height -= 1;
}
public void visit_ifle(final Instruction inst) {
height -= 1;
}
public void visit_if_icmpeq(final Instruction inst) {
height -= 2;
}
public void visit_if_icmpne(final Instruction inst) {
height -= 2;
}
public void visit_if_icmplt(final Instruction inst) {
height -= 2;
}
public void visit_if_icmpge(final Instruction inst) {
height -= 2;
}
public void visit_if_icmpgt(final Instruction inst) {
height -= 2;
}
public void visit_if_icmple(final Instruction inst) {
height -= 2;
}
public void visit_if_acmpeq(final Instruction inst) {
height -= 2;
}
public void visit_if_acmpne(final Instruction inst) {
height -= 2;
}
public void visit_jsr(final Instruction inst) {
// Even though the jsr instruction itself pushes the return
// address onto the stack, we don't want to account for that
// here. It is already taken care of in the handle method. This
// way the label following the jsr (the return site) will have the
// stack height it had before the call. Once again, we do not
// account for the possibility of the jsr modifying the height of
// the stack.
height += 0;
}
public void visit_switch(final Instruction inst) {
height -= 1;
}
public void visit_ireturn(final Instruction inst) {
height = 0;
}
public void visit_lreturn(final Instruction inst) {
height = 0;
}
public void visit_freturn(final Instruction inst) {
height = 0;
}
public void visit_dreturn(final Instruction inst) {
height = 0;
}
public void visit_areturn(final Instruction inst) {
height = 0;
}
public void visit_return(final Instruction inst) {
height = 0;
}
public void visit_getstatic(final Instruction inst) {
final Type type = ((MemberRef) inst.operand()).nameAndType().type();
height += type.stackHeight();
}
public void visit_putstatic(final Instruction inst) {
final Type type = ((MemberRef) inst.operand()).nameAndType().type();
height -= type.stackHeight();
}
public void visit_putstatic_nowb(final Instruction inst) {
final Type type = ((MemberRef) inst.operand()).nameAndType().type();
height -= type.stackHeight();
}
public void visit_getfield(final Instruction inst) {
final Type type = ((MemberRef) inst.operand()).nameAndType().type();
height += type.stackHeight() - 1;
}
public void visit_putfield(final Instruction inst) {
final Type type = ((MemberRef) inst.operand()).nameAndType().type();
height -= type.stackHeight() + 1;
}
public void visit_putfield_nowb(final Instruction inst) {
final Type type = ((MemberRef) inst.operand()).nameAndType().type();
height -= type.stackHeight() + 1;
}
public void visit_invokevirtual(final Instruction inst) {
final MemberRef method = (MemberRef) inst.operand();
final Type type = method.nameAndType().type();
height += type.returnType().stackHeight() - type.stackHeight() - 1;
}
public void visit_invokespecial(final Instruction inst) {
final MemberRef method = (MemberRef) inst.operand();
final Type type = method.nameAndType().type();
height += type.returnType().stackHeight() - type.stackHeight() - 1;
}
public void visit_invokestatic(final Instruction inst) {
final MemberRef method = (MemberRef) inst.operand();
final Type type = method.nameAndType().type();
height += type.returnType().stackHeight() - type.stackHeight();
}
public void visit_invokeinterface(final Instruction inst) {
final MemberRef method = (MemberRef) inst.operand();
final Type type = method.nameAndType().type();
height += type.returnType().stackHeight() - type.stackHeight() - 1;
}
public void visit_new(final Instruction inst) {
height += 1;
}
public void visit_monitorenter(final Instruction inst) {
height -= 1;
}
public void visit_monitorexit(final Instruction inst) {
height -= 1;
}
public void visit_multianewarray(final Instruction inst) {
final MultiArrayOperand operand = (MultiArrayOperand) inst.operand();
final int dim = operand.dimensions();
height += 1 - dim;
}
public void visit_ifnull(final Instruction inst) {
height -= 1;
}
public void visit_ifnonnull(final Instruction inst) {
height -= 1;
}
public void visit_aswizzle(final Instruction inst) {
height -= 2;
}
public void visit_aswrange(final Instruction inst) {
height -= 3;
}
/**
* Returns a clone of this <tt>StackHeightCounter</tt>
*/
public Object clone() {
final StackHeightCounter clone = new StackHeightCounter(this.method);
clone.height = this.height;
clone.labelHeights = (HashMap) this.labelHeights.clone();
return (clone);
}
}