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/editor/CodeArray.java

2408 lines
55 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.editor;
import java.util.*;
import EDU.purdue.cs.bloat.reflect.*;
import EDU.purdue.cs.bloat.util.*;
/**
* CodeArray converts an array of Instructions into an array of bytes suitable
* for saving to a <tt>MethodInfo</tt> with <tt>setCode</tt>.
*
* <p>
*
* The byte array is returned by calling the <tt>array</tt> method.
*
* <p>
*
* This code assumes no branch will be longer than 65536 bytes.
*
* @see Instruction
* @see MethodInfo
* @see MethodInfo#setCode
*
* @author Nate Nystrom (<a
* href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>)
*/
public class CodeArray implements InstructionVisitor, Opcode {
public static boolean DEBUG = Boolean.getBoolean("CodeArray.DEBUG");
private ByteCell codeTail; // Linked list of ByteCells representing code
private int codeLength; // Number of bytes in method
private Map branches;
private Map longBranches;
private Map branchInsts;
private Map labels; // Labels mapped to their offsets
private int lastInst; // Offset of last (most recent) instrucion
private int maxStack; // Max stack height
private int stackHeight; // Current stack height
private int maxLocals; // Max number of local variables
private ConstantPool constants;
private MethodEditor method;
private boolean longBranch; // Do we use long (wide) jumps?
private List insts;
/**
* Create the byte array for a method.
*
* @param method
* The method being edited.
* @param constants
* The constant pool of the class.
* @param insts
* A List of Instructions and Labels to convert to a byte array.
* @see MethodEditor
* @see ConstantPool
* @see Instruction
* @see Label
*/
public CodeArray(final MethodEditor method, final ConstantPool constants,
final List insts) {
this.constants = constants;
this.method = method;
this.insts = insts;
this.maxStack = 0;
this.maxLocals = 0;
longBranch = false;
buildCode();
}
/**
* Examine the method's Labels and Instructions. Keep track of such things
* as the height of the stack at each instruction and to where subroutines
* return. The ultimate goal is to compute the max stack height of this
* method. This computation is complicated by subroutines that may be
* invoked at a variety of stack heights.
*/
private void buildCode() {
codeTail = null;
codeLength = 0;
branches = new HashMap();
longBranches = new HashMap();
branchInsts = new HashMap();
labels = new HashMap();
// We need at least enought locals to store the parameters
maxLocals = method.type().stackHeight();
if (!method.isStatic()) {
// One more for the this pointer
maxLocals++;
}
stackHeight = 0;
final Map labelPos = new HashMap(); // Maps Labels to their code offsets
final int[] heights = new int[insts.size()]; // Stack height at each
// inst
// Maps Labels that begin jsrs to their return targets. Maps ret
// instructions to the subroutine from which they return.
final Map retTargets = new HashMap();
final Map retInsts = new HashMap();
// Print the code we're dealing with
if (CodeArray.DEBUG) {
System.out.println("Building code for "
+ method.declaringClass().name() + "." + method.name());
final Iterator iter = insts.iterator();
while (iter.hasNext()) {
final Object o = iter.next();
System.out.println(" " + o);
}
}
// Build the bytecode array, assuming each basic block begins with
// stack height 0. We'll fix up the heights later.
final Iterator iter = insts.iterator();
int i = 0; // Which instruction are we at?
while (iter.hasNext()) {
final Object ce = iter.next();
if (ce instanceof Label) {
final Label label = (Label) ce;
// A Label starts a new basic block. Reset the stack height.
stackHeight = 0;
labelPos.put(label, new Integer(i));
addLabel(label);
heights[i++] = stackHeight;
// If this label starts a subroutine (i.e. is the target of
// jsr instruction), then make not of it.
if (retTargets.containsKey(label)) {
}
} else if (ce instanceof Instruction) {
final Instruction inst = (Instruction) ce;
// Visit this instruction to compute the current stack height
inst.visit(this);
if (inst.isJsr()) {
// Make sure that the jsr is not the last instruction in the
// method. If it was, where would we return to? Make note
// of the return target (the Label following the jsr).
heights[i++] = stackHeight;
Assert.isTrue(iter.hasNext(), inst
+ " found at end of method");
final Object x = iter.next();
Assert.isTrue(x instanceof Label, inst
+ " not followed by label");
final Label sub = (Label) inst.operand();
final Label target = (Label) x;
// Maintain a mapping between a subroutine (the Label that
// begins it) and all return targets.
Set targets = (Set) retTargets.get(sub);
if (targets == null) {
targets = new HashSet();
retTargets.put(sub, targets);
}
targets.add(target);
stackHeight = 0;
labelPos.put(target, new Integer(i));
addLabel(target);
heights[i++] = stackHeight;
} else {
heights[i++] = stackHeight;
}
} else {
// Something bad in instruction list
throw new IllegalArgumentException();
}
}
// Sorry, but we have to make another forward pass over some of
// the code to determine the subroutine from which a given ret
// instruction returns.
final Iterator subLabels = retTargets.keySet().iterator();
while (subLabels.hasNext()) {
final Label subLabel = (Label) subLabels.next();
final int pos = insts.indexOf(subLabel);
Assert.isTrue(pos != -1, "Label " + subLabel + " not found");
boolean foundRet = false;
final ListIterator liter = insts.listIterator(pos);
while (liter.hasNext()) {
final Object o = liter.next();
if (o instanceof Instruction) {
final Instruction inst = (Instruction) o;
if (inst.isRet()) {
retInsts.put(inst, subLabel);
foundRet = true;
break;
}
}
}
Assert.isTrue(foundRet, "No ret for subroutine " + subLabel);
}
if (CodeArray.DEBUG) {
// Print subroutine to return target mapping
System.out.println("Subroutines and return targets:");
final Iterator subs = retTargets.keySet().iterator();
while (subs.hasNext()) {
final Label sub = (Label) subs.next();
System.out.print(" " + sub + ": ");
final Set s = (Set) retTargets.get(sub);
Assert.isTrue(s != null, "No return targets for " + sub);
final Iterator rets = s.iterator();
while (rets.hasNext()) {
final Label ret = (Label) rets.next();
System.out.print(ret.toString());
if (rets.hasNext()) {
System.out.print(", ");
}
}
System.out.println("");
}
}
// Fix up the stack heights by propagating the heights at each catch
// and each branch to their targets. Visit the blocks
// depth-first. Remember that the classfile requires the maximum
// stack height. I would assume that is why we do all of this
// stack height calculation stuff.
final Set visited = new HashSet(); // Labels that we've seen
final Stack stack = new Stack(); // Stack of HeightRecords
Label label;
// Start with the first Label
if (insts.size() > 0) {
Assert.isTrue((insts.get(0) instanceof Label),
"A method must begin with a Label, not " + insts.get(0));
label = (Label) insts.get(0);
visited.add(label);
stack.push(new HeightRecord(label, 0));
}
// Also examine each exception handler. Recall that the exception
// object is implicitly pushed on the stack. So, the HeightRecord
// initially has height 1.
final Iterator e = method.tryCatches().iterator();
while (e.hasNext()) {
final TryCatch tc = (TryCatch) e.next();
visited.add(tc.handler());
stack.push(new HeightRecord(tc.handler(), 1));
}
// Examine the HeightRecords on the stack. Make sure that the
// stack height has not exceeded 256. If the height at a given
// label has changed since we last visited it, then propagate this
// change to labels following the block begun by the label in
// question.
while (!stack.isEmpty()) {
final HeightRecord h = (HeightRecord) stack.pop();
Assert.isTrue(h.height < 256, "Stack height of " + h.height
+ " reached. " + h.label + " (" + labelPos.get(h.label)
+ ")");
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(h.label + " has height " + h.height);
}
Integer labelIndex = (Integer) labelPos.get(h.label);
Assert.isTrue(labelIndex != null, "Index of " + h.label
+ " not found");
final int start = labelIndex.intValue();
int diff = h.height - heights[start];
// Propagate the change in height to the next branch.
// Then push the branch targets.
if (ClassEditor.DEBUG) {
/*
* System.out.println(" " + h.label + ": change " +
* heights[start] + " to " + h.height);
*/
}
heights[start] = h.height;
final ListIterator blockIter = insts.listIterator(start + 1);
i = start;
// Examine the instructions following the label
while (blockIter.hasNext()) {
final Object ce = blockIter.next();
i++;
if (ce instanceof Instruction) {
final Instruction inst = (Instruction) ce;
if (inst.isReturn() || inst.isThrow()) {
// The method terminates. The stack is popped empty.
heights[i] = 0;
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" " + heights[i] + ") " + inst);
}
// Consider next HeightRecord on stack.
break;
} else if (inst.isConditionalJump()) {
// If the stack height at this Label has changed since
// we
// last saw it or if we have not processed the target of
// the jump, add a new HeightRecord for the target
// Label.
heights[i] += diff;
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" " + heights[i] + ") " + inst);
}
label = (Label) inst.operand();
if ((diff > 0) || !visited.contains(label)) {
visited.add(label);
stack.push(new HeightRecord(label, heights[i]));
}
// Fall through. That is, process the instruction after
// the conditional jump. Remember that the code is in
// trace order so the false block (which is the next
// block
// in a depth first traversal) follows. The height of
// the
// stack won't change when we fall through.
} else if (inst.isGoto() || inst.isJsr()) {
// Once again, if we have already visited the target
// block, add a HeightRecord to the stack.
heights[i] += diff;
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" " + heights[i] + ") " + inst);
}
label = (Label) inst.operand();
if ((diff > 0) || !visited.contains(label)) {
visited.add(label);
stack.push(new HeightRecord(label, heights[i]));
}
// Deal with the next HeightRecord on the stack.
break;
} else if (inst.isRet()) {
// Process any unvisited return targets (of the current
// jsr) or those whose current height is less than the
// height at this return instruction.
heights[i] += diff;
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" " + heights[i] + ") " + inst);
}
final Label subLabel = (Label) retInsts.get(inst);
Assert.isTrue(subLabel != null,
"Not inside a subroutine at " + inst);
final Set targets = (Set) retTargets.get(subLabel);
Assert.isTrue(targets != null, "Subroutine " + subLabel
+ " has no return targets");
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" Returning from: "
+ subLabel);
}
final Iterator retIter = targets.iterator();
while (retIter.hasNext()) {
label = (Label) retIter.next();
labelIndex = (Integer) labelPos.get(label);
Assert.isTrue(labelIndex != null, "Index of "
+ label + " not found");
final int idx = labelIndex.intValue();
if ((heights[idx] < heights[i])
|| !visited.contains(label)) {
visited.add(label);
stack.push(new HeightRecord(label, heights[i]));
}
}
break;
} else if (inst.isSwitch()) {
// Visit each unvisited switch target if it increases
// the
// stack height
// If the height at this Label has changed since it was
// last visited, process each target Label. Otherwise,
// only process unvisited Labels.
heights[i] += diff;
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" " + heights[i] + ") " + inst);
}
// A switch.
final Switch sw = (Switch) inst.operand();
label = sw.defaultTarget();
if ((diff > 0) || !visited.contains(label)) {
visited.add(label);
stack.push(new HeightRecord(label, heights[i]));
}
final Label[] targets = sw.targets();
for (int j = 0; j < targets.length; j++) {
label = targets[j];
if ((diff > 0) || !visited.contains(label)) {
visited.add(label);
stack.push(new HeightRecord(label, heights[i]));
}
}
break;
} else {
// No other blocks to visit. Just adjust the height.
heights[i] += diff;
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" " + heights[i] + ") " + inst);
}
}
} else if (ce instanceof Label) {
// We've hit the next block. Update the stack height.
// Process this next block if has not been visited or its
// current height is different from the previous
// instruction.
label = (Label) ce;
diff = heights[i - 1] - heights[i];
if ((diff > 0) || !visited.contains(label)) {
visited.add(label);
heights[i] = heights[i - 1];
}
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" " + heights[i] + ") " + label);
}
}
}
}
// Find the maximum stack height.
maxStack = 0;
for (i = 0; i < heights.length; i++) {
final int h = heights[i];
if (h > maxStack) {
maxStack = h;
}
}
}
/**
* Returns the maximum number of local variables used by this method.
*/
public int maxLocals() {
return maxLocals;
}
/**
* Returns the maximum height of the stack at any point in this method.
*/
public int maxStack() {
return maxStack;
}
/**
* Returns the index in the byte array of the given label.
*/
public int labelIndex(final Label label) {
final Integer i = (Integer) labels.get(label);
if (i != null) {
return i.intValue();
}
throw new IllegalArgumentException("Label " + label + " not found");
}
/**
* Returns the byte array after resolving branches.
*/
public byte[] array() {
if (branches.size() > 0) {
if (!longBranch && (codeLength >= 0x10000)) {
longBranch = true;
buildCode();
}
}
final byte[] c = new byte[codeLength];
int i = codeLength;
for (ByteCell p = codeTail; p != null; p = p.prev) {
c[--i] = p.value;
}
Iterator e;
e = branches.keySet().iterator();
while (e.hasNext()) {
final Integer branch = (Integer) e.next();
final int branchIndex = branch.intValue();
final Integer inst = (Integer) branchInsts.get(branch);
final int instIndex = inst.intValue();
final Label label = (Label) branches.get(branch);
final Integer target = (Integer) labels.get(label);
Assert.isTrue(target != null, "Index of " + label + " not found");
int diff = target.intValue() - instIndex;
Assert.isTrue((-diff < 0x10000) && (diff < 0x10000),
"Branch offset too large: " + diff);
c[branchIndex] = (byte) ((diff >>> 8) & 0xff);
c[branchIndex + 1] = (byte) (diff & 0xff);
}
e = longBranches.keySet().iterator();
while (e.hasNext()) {
final Integer branch = (Integer) e.next();
final int branchIndex = branch.intValue();
final Integer inst = (Integer) branchInsts.get(branch);
final int instIndex = inst.intValue();
final Label label = (Label) longBranches.get(branch);
final Integer target = (Integer) labels.get(label);
final int diff = target.intValue() - instIndex;
c[branchIndex] = (byte) ((diff >>> 24) & 0xff);
c[branchIndex + 1] = (byte) ((diff >>> 16) & 0xff);
c[branchIndex + 2] = (byte) ((diff >>> 8) & 0xff);
c[branchIndex + 3] = (byte) (diff & 0xff);
}
return c;
}
/**
* Makes note of a label.
*/
public void addLabel(final Label label) {
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" " + codeLength + ": " + "label " + label);
}
labels.put(label, new Integer(codeLength));
}
/**
* Adds a 4-byte branch to a given label. The branch is from the index of
* the last opcode added.
*/
public void addLongBranch(final Label label) {
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" " + codeLength + ": " + "long branch to "
+ label);
}
branchInsts.put(new Integer(codeLength), new Integer(lastInst));
longBranches.put(new Integer(codeLength), label);
addByte(0);
addByte(0);
addByte(0);
addByte(0);
}
/**
* Adds a 2-byte branch to a given label. The branch is from the index of
* the last opcode added.
*/
public void addBranch(final Label label) {
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" " + codeLength + ": " + "branch to "
+ label);
}
branchInsts.put(new Integer(codeLength), new Integer(lastInst));
branches.put(new Integer(codeLength), label);
addByte(0);
addByte(0);
}
/**
* Add an opcode to the byte array, adjusting for 4-byte alignment for
* switch instructions and saving the index for calculating branches.
*
* @param opcode
* The opcode.
* @see Opcode
*/
public void addOpcode(final int opcode) {
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" " + codeLength + ": " + "opcode "
+ Opcode.opcNames[opcode]);
}
lastInst = codeLength;
addByte(opcode);
if ((opcode == Opcode.opc_tableswitch)
|| (opcode == Opcode.opc_lookupswitch)) {
// Switch instructions are followed by padding so that table
// starts on a 4-byte boundary.
while (codeLength % 4 != 0) {
addByte(0);
}
}
}
/**
* Adds a single byte to the array.
*/
public void addByte(final int i) {
if (ClassEditor.DEBUG) {
System.out.println(" " + codeLength + ": " + "byte " + i);
}
// The bytecode array is represented as a linked list of
// ByteCells. This method creates a new ByteCell and appends it
// to the linked list.
final ByteCell p = new ByteCell();
p.value = (byte) (i & 0xff);
p.prev = codeTail;
codeTail = p;
codeLength++;
}
/**
* Adds a 2-byte short to the array, high byte first.
*/
public void addShort(final int i) {
if (ClassEditor.DEBUG) {
System.out.println(" " + codeLength + ": " + "short " + i);
}
addByte(i >>> 8);
addByte(i);
}
/**
* Adds a 4-byte int to the array, high byte first.
*/
public void addInt(final int i) {
if (ClassEditor.DEBUG) {
System.out.println(" " + codeLength + ": " + "int " + i);
}
addByte(i >>> 24);
addByte(i >>> 16);
addByte(i >>> 8);
addByte(i);
}
public void visit_nop(final Instruction inst) {
// If it must have been put there for a reason.
addOpcode(Opcode.opc_nop);
stackHeight += 0;
}
/*
* Does pretty much what you'd expect. Examines the instruction's operand to
* determine if one of the special constant opcodes (e.g. iconst_1) can be
* used. Adds the most appropriate instruction.
*/
public void visit_ldc(final Instruction inst) {
final Object operand = inst.operand();
if (operand == null) {
addOpcode(Opcode.opc_aconst_null);
stackHeight++;
} else if (operand instanceof Integer) {
final int v = ((Integer) operand).intValue();
switch (v) {
case -1:
addOpcode(Opcode.opc_iconst_m1);
break;
case 0:
addOpcode(Opcode.opc_iconst_0);
break;
case 1:
addOpcode(Opcode.opc_iconst_1);
break;
case 2:
addOpcode(Opcode.opc_iconst_2);
break;
case 3:
addOpcode(Opcode.opc_iconst_3);
break;
case 4:
addOpcode(Opcode.opc_iconst_4);
break;
case 5:
addOpcode(Opcode.opc_iconst_5);
break;
default: {
if ((byte) v == v) {
addOpcode(Opcode.opc_bipush);
addByte(v);
} else if ((short) v == v) {
addOpcode(Opcode.opc_sipush);
addShort(v);
} else {
final int index = constants.addConstant(Constant.INTEGER,
operand);
if (index < 256) {
addOpcode(Opcode.opc_ldc);
addByte(index);
} else {
addOpcode(Opcode.opc_ldc_w);
addShort(index);
}
}
break;
}
}
stackHeight++;
} else if (operand instanceof Float) {
final float v = ((Float) operand).floatValue();
if (v == 0.0F) {
addOpcode(Opcode.opc_fconst_0);
} else if (v == 1.0F) {
addOpcode(Opcode.opc_fconst_1);
} else if (v == 2.0F) {
addOpcode(Opcode.opc_fconst_2);
} else {
final int index = constants
.addConstant(Constant.FLOAT, operand);
if (index < 256) {
addOpcode(Opcode.opc_ldc);
addByte(index);
} else {
addOpcode(Opcode.opc_ldc_w);
addShort(index);
}
}
stackHeight++;
} else if (operand instanceof Long) {
final long v = ((Long) operand).longValue();
if (v == 0) {
addOpcode(Opcode.opc_lconst_0);
} else if (v == 1) {
addOpcode(Opcode.opc_lconst_1);
} else {
final int index = constants.addConstant(Constant.LONG, operand);
addOpcode(Opcode.opc_ldc2_w);
addShort(index);
}
stackHeight += 2;
} else if (operand instanceof Double) {
final double v = ((Double) operand).doubleValue();
if (v == 0.0) {
addOpcode(Opcode.opc_dconst_0);
} else if (v == 1.0) {
addOpcode(Opcode.opc_dconst_1);
} else {
final int index = constants.addConstant(Constant.DOUBLE,
operand);
addOpcode(Opcode.opc_ldc2_w);
addShort(index);
}
stackHeight += 2;
} else if (operand instanceof String) {
final int index = constants.addConstant(Constant.STRING, operand);
if (index < 256) {
addOpcode(Opcode.opc_ldc);
addByte(index);
} else {
addOpcode(Opcode.opc_ldc_w);
addShort(index);
}
stackHeight++;
} else {
throw new RuntimeException();
}
}
/*
* Tries to use the shorter iload_x instructions.
*/
public void visit_iload(final Instruction inst) {
final int index = ((LocalVariable) inst.operand()).index();
if (index + 1 > maxLocals) {
maxLocals = index + 1;
}
if (inst.useSlow()) {
if (index < 256) {
addOpcode(Opcode.opc_iload);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_iload);
addShort(index);
}
stackHeight++;
return;
}
switch (index) {
case 0:
addOpcode(Opcode.opc_iload_0);
break;
case 1:
addOpcode(Opcode.opc_iload_1);
break;
case 2:
addOpcode(Opcode.opc_iload_2);
break;
case 3:
addOpcode(Opcode.opc_iload_3);
break;
default:
if (index < 256) {
addOpcode(Opcode.opc_iload);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_iload);
addShort(index);
}
break;
}
stackHeight++;
}
public void visit_lload(final Instruction inst) {
final int index = ((LocalVariable) inst.operand()).index();
if (index + 2 > maxLocals) {
maxLocals = index + 2;
}
if (inst.useSlow()) {
if (index < 256) {
addOpcode(Opcode.opc_lload);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_lload);
addShort(index);
}
stackHeight++;
return;
}
switch (index) {
case 0:
addOpcode(Opcode.opc_lload_0);
break;
case 1:
addOpcode(Opcode.opc_lload_1);
break;
case 2:
addOpcode(Opcode.opc_lload_2);
break;
case 3:
addOpcode(Opcode.opc_lload_3);
break;
default:
if (index < 256) {
addOpcode(Opcode.opc_lload);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_lload);
addShort(index);
}
break;
}
stackHeight += 2;
}
public void visit_fload(final Instruction inst) {
final int index = ((LocalVariable) inst.operand()).index();
if (index + 1 > maxLocals) {
maxLocals = index + 1;
}
if (inst.useSlow()) {
if (index < 256) {
addOpcode(Opcode.opc_fload);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_fload);
addShort(index);
}
stackHeight++;
return;
}
switch (index) {
case 0:
addOpcode(Opcode.opc_fload_0);
break;
case 1:
addOpcode(Opcode.opc_fload_1);
break;
case 2:
addOpcode(Opcode.opc_fload_2);
break;
case 3:
addOpcode(Opcode.opc_fload_3);
break;
default:
if (index < 256) {
addOpcode(Opcode.opc_fload);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_fload);
addShort(index);
}
break;
}
stackHeight++;
}
public void visit_dload(final Instruction inst) {
final int index = ((LocalVariable) inst.operand()).index();
if (index + 2 > maxLocals) {
maxLocals = index + 2;
}
if (inst.useSlow()) {
if (index < 256) {
addOpcode(Opcode.opc_dload);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_dload);
addShort(index);
}
stackHeight += 2;
return;
}
switch (index) {
case 0:
addOpcode(Opcode.opc_dload_0);
break;
case 1:
addOpcode(Opcode.opc_dload_1);
break;
case 2:
addOpcode(Opcode.opc_dload_2);
break;
case 3:
addOpcode(Opcode.opc_dload_3);
break;
default:
if (index < 256) {
addOpcode(Opcode.opc_dload);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_dload);
addShort(index);
}
break;
}
stackHeight += 2;
}
public void visit_aload(final Instruction inst) {
final int index = ((LocalVariable) inst.operand()).index();
if (index + 1 > maxLocals) {
maxLocals = index + 1;
}
if (inst.useSlow()) {
if (index < 256) {
addOpcode(Opcode.opc_aload);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_aload);
addShort(index);
}
stackHeight++;
return;
}
switch (index) {
case 0:
addOpcode(Opcode.opc_aload_0);
break;
case 1:
addOpcode(Opcode.opc_aload_1);
break;
case 2:
addOpcode(Opcode.opc_aload_2);
break;
case 3:
addOpcode(Opcode.opc_aload_3);
break;
default:
if (index < 256) {
addOpcode(Opcode.opc_aload);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_aload);
addShort(index);
}
break;
}
stackHeight++;
}
/**
* Pops an item off the stack.
*/
public void visit_iaload(final Instruction inst) {
addOpcode(Opcode.opc_iaload);
stackHeight--;
}
public void visit_laload(final Instruction inst) {
addOpcode(Opcode.opc_laload);
stackHeight += 0;
}
public void visit_faload(final Instruction inst) {
addOpcode(Opcode.opc_faload);
stackHeight--;
}
public void visit_daload(final Instruction inst) {
addOpcode(Opcode.opc_daload);
stackHeight += 0;
}
public void visit_aaload(final Instruction inst) {
addOpcode(Opcode.opc_aaload);
stackHeight--;
}
public void visit_baload(final Instruction inst) {
addOpcode(Opcode.opc_baload);
stackHeight--;
}
public void visit_caload(final Instruction inst) {
addOpcode(Opcode.opc_caload);
stackHeight--;
}
public void visit_saload(final Instruction inst) {
addOpcode(Opcode.opc_saload);
stackHeight--;
}
/*
* Try to take advantage of smaller opcodes (e.g. istore_1).
*/
public void visit_istore(final Instruction inst) {
final int index = ((LocalVariable) inst.operand()).index();
if (index + 1 > maxLocals) {
maxLocals = index + 1;
}
if (inst.useSlow()) {
if (index < 256) {
addOpcode(Opcode.opc_istore);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_istore);
addShort(index);
}
stackHeight--;
return;
}
switch (index) {
case 0:
addOpcode(Opcode.opc_istore_0);
break;
case 1:
addOpcode(Opcode.opc_istore_1);
break;
case 2:
addOpcode(Opcode.opc_istore_2);
break;
case 3:
addOpcode(Opcode.opc_istore_3);
break;
default:
if (index < 256) {
addOpcode(Opcode.opc_istore);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_istore);
addShort(index);
}
break;
}
stackHeight--;
}
public void visit_lstore(final Instruction inst) {
final int index = ((LocalVariable) inst.operand()).index();
if (index + 2 > maxLocals) {
maxLocals = index + 2;
}
if (inst.useSlow()) {
if (index < 256) {
addOpcode(Opcode.opc_lstore);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_lstore);
addShort(index);
}
stackHeight -= 2;
return;
}
switch (index) {
case 0:
addOpcode(Opcode.opc_lstore_0);
break;
case 1:
addOpcode(Opcode.opc_lstore_1);
break;
case 2:
addOpcode(Opcode.opc_lstore_2);
break;
case 3:
addOpcode(Opcode.opc_lstore_3);
break;
default:
if (index < 256) {
addOpcode(Opcode.opc_lstore);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_lstore);
addShort(index);
}
break;
}
stackHeight -= 2;
}
public void visit_fstore(final Instruction inst) {
final int index = ((LocalVariable) inst.operand()).index();
if (index + 1 > maxLocals) {
maxLocals = index + 1;
}
if (inst.useSlow()) {
if (index < 256) {
addOpcode(Opcode.opc_fstore);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_fstore);
addShort(index);
}
stackHeight--;
return;
}
switch (index) {
case 0:
addOpcode(Opcode.opc_fstore_0);
break;
case 1:
addOpcode(Opcode.opc_fstore_1);
break;
case 2:
addOpcode(Opcode.opc_fstore_2);
break;
case 3:
addOpcode(Opcode.opc_fstore_3);
break;
default:
if (index < 256) {
addOpcode(Opcode.opc_fstore);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_fstore);
addShort(index);
}
break;
}
stackHeight--;
}
public void visit_dstore(final Instruction inst) {
final int index = ((LocalVariable) inst.operand()).index();
if (index + 2 > maxLocals) {
maxLocals = index + 2;
}
if (inst.useSlow()) {
if (index < 256) {
addOpcode(Opcode.opc_dstore);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_dstore);
addShort(index);
}
stackHeight -= 2;
return;
}
switch (index) {
case 0:
addOpcode(Opcode.opc_dstore_0);
break;
case 1:
addOpcode(Opcode.opc_dstore_1);
break;
case 2:
addOpcode(Opcode.opc_dstore_2);
break;
case 3:
addOpcode(Opcode.opc_dstore_3);
break;
default:
if (index < 256) {
addOpcode(Opcode.opc_dstore);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_dstore);
addShort(index);
}
break;
}
stackHeight -= 2;
}
public void visit_astore(final Instruction inst) {
final int index = ((LocalVariable) inst.operand()).index();
if (index + 1 > maxLocals) {
maxLocals = index + 1;
}
if (inst.useSlow()) {
if (index < 256) {
addOpcode(Opcode.opc_astore);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_astore);
addShort(index);
}
stackHeight--;
return;
}
switch (index) {
case 0:
addOpcode(Opcode.opc_astore_0);
break;
case 1:
addOpcode(Opcode.opc_astore_1);
break;
case 2:
addOpcode(Opcode.opc_astore_2);
break;
case 3:
addOpcode(Opcode.opc_astore_3);
break;
default:
if (index < 256) {
addOpcode(Opcode.opc_astore);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_astore);
addShort(index);
}
break;
}
stackHeight--;
}
/*
* Store into an array. Pop 3+ items off the stack.
*/
public void visit_iastore(final Instruction inst) {
addOpcode(Opcode.opc_iastore);
stackHeight -= 3;
}
public void visit_lastore(final Instruction inst) {
addOpcode(Opcode.opc_lastore);
stackHeight -= 4;
}
public void visit_fastore(final Instruction inst) {
addOpcode(Opcode.opc_fastore);
stackHeight -= 3;
}
public void visit_dastore(final Instruction inst) {
addOpcode(Opcode.opc_dastore);
stackHeight -= 4;
}
public void visit_aastore(final Instruction inst) {
addOpcode(Opcode.opc_aastore);
stackHeight -= 3;
}
public void visit_bastore(final Instruction inst) {
addOpcode(Opcode.opc_bastore);
stackHeight -= 3;
}
public void visit_castore(final Instruction inst) {
addOpcode(Opcode.opc_castore);
stackHeight -= 3;
}
public void visit_sastore(final Instruction inst) {
addOpcode(Opcode.opc_sastore);
stackHeight -= 3;
}
public void visit_pop(final Instruction inst) {
addOpcode(Opcode.opc_pop);
stackHeight--;
}
public void visit_pop2(final Instruction inst) {
addOpcode(Opcode.opc_pop2);
stackHeight -= 2;
}
public void visit_dup(final Instruction inst) {
addOpcode(Opcode.opc_dup);
stackHeight++;
}
public void visit_dup_x1(final Instruction inst) {
addOpcode(Opcode.opc_dup_x1);
stackHeight++;
}
public void visit_dup_x2(final Instruction inst) {
addOpcode(Opcode.opc_dup_x2);
stackHeight++;
}
public void visit_dup2(final Instruction inst) {
addOpcode(Opcode.opc_dup2);
stackHeight += 2;
}
public void visit_dup2_x1(final Instruction inst) {
addOpcode(Opcode.opc_dup2_x1);
stackHeight += 2;
}
public void visit_dup2_x2(final Instruction inst) {
addOpcode(Opcode.opc_dup2_x2);
stackHeight += 2;
}
public void visit_swap(final Instruction inst) {
addOpcode(Opcode.opc_swap);
}
public void visit_iadd(final Instruction inst) {
addOpcode(Opcode.opc_iadd);
stackHeight--;
}
public void visit_ladd(final Instruction inst) {
addOpcode(Opcode.opc_ladd);
stackHeight -= 2;
}
public void visit_fadd(final Instruction inst) {
addOpcode(Opcode.opc_fadd);
stackHeight--;
}
public void visit_dadd(final Instruction inst) {
addOpcode(Opcode.opc_dadd);
stackHeight -= 2;
}
public void visit_isub(final Instruction inst) {
addOpcode(Opcode.opc_isub);
stackHeight--;
}
public void visit_lsub(final Instruction inst) {
addOpcode(Opcode.opc_lsub);
stackHeight -= 2;
}
public void visit_fsub(final Instruction inst) {
addOpcode(Opcode.opc_fsub);
stackHeight--;
}
public void visit_dsub(final Instruction inst) {
addOpcode(Opcode.opc_dsub);
stackHeight -= 2;
}
public void visit_imul(final Instruction inst) {
addOpcode(Opcode.opc_imul);
stackHeight--;
}
public void visit_lmul(final Instruction inst) {
addOpcode(Opcode.opc_lmul);
stackHeight -= 2;
}
public void visit_fmul(final Instruction inst) {
addOpcode(Opcode.opc_fmul);
stackHeight--;
}
public void visit_dmul(final Instruction inst) {
addOpcode(Opcode.opc_dmul);
stackHeight -= 2;
}
public void visit_idiv(final Instruction inst) {
addOpcode(Opcode.opc_idiv);
stackHeight--;
}
public void visit_ldiv(final Instruction inst) {
addOpcode(Opcode.opc_ldiv);
stackHeight -= 2;
}
public void visit_fdiv(final Instruction inst) {
addOpcode(Opcode.opc_fdiv);
stackHeight--;
}
public void visit_ddiv(final Instruction inst) {
addOpcode(Opcode.opc_ddiv);
stackHeight -= 2;
}
public void visit_irem(final Instruction inst) {
addOpcode(Opcode.opc_irem);
stackHeight--;
}
public void visit_lrem(final Instruction inst) {
addOpcode(Opcode.opc_lrem);
stackHeight -= 2;
}
public void visit_frem(final Instruction inst) {
addOpcode(Opcode.opc_frem);
stackHeight--;
}
public void visit_drem(final Instruction inst) {
addOpcode(Opcode.opc_drem);
stackHeight -= 2;
}
public void visit_ineg(final Instruction inst) {
addOpcode(Opcode.opc_ineg);
stackHeight += 0;
}
public void visit_lneg(final Instruction inst) {
addOpcode(Opcode.opc_lneg);
stackHeight += 0;
}
public void visit_fneg(final Instruction inst) {
addOpcode(Opcode.opc_fneg);
stackHeight += 0;
}
public void visit_dneg(final Instruction inst) {
addOpcode(Opcode.opc_dneg);
stackHeight += 0;
}
public void visit_ishl(final Instruction inst) {
addOpcode(Opcode.opc_ishl);
stackHeight--;
}
public void visit_lshl(final Instruction inst) {
addOpcode(Opcode.opc_lshl);
stackHeight--;
}
public void visit_ishr(final Instruction inst) {
addOpcode(Opcode.opc_ishr);
stackHeight--;
}
public void visit_lshr(final Instruction inst) {
addOpcode(Opcode.opc_lshr);
stackHeight--;
}
public void visit_iushr(final Instruction inst) {
addOpcode(Opcode.opc_iushr);
stackHeight--;
}
public void visit_lushr(final Instruction inst) {
addOpcode(Opcode.opc_lushr);
stackHeight--;
}
public void visit_iand(final Instruction inst) {
addOpcode(Opcode.opc_iand);
stackHeight--;
}
public void visit_land(final Instruction inst) {
addOpcode(Opcode.opc_land);
stackHeight -= 2;
}
public void visit_ior(final Instruction inst) {
addOpcode(Opcode.opc_ior);
stackHeight--;
}
public void visit_lor(final Instruction inst) {
addOpcode(Opcode.opc_lor);
stackHeight -= 2;
}
public void visit_ixor(final Instruction inst) {
addOpcode(Opcode.opc_ixor);
stackHeight--;
}
public void visit_lxor(final Instruction inst) {
addOpcode(Opcode.opc_lxor);
stackHeight -= 2;
}
public void visit_iinc(final Instruction inst) {
final IncOperand operand = (IncOperand) inst.operand();
final int index = operand.var().index();
if (index + 1 > maxLocals) {
maxLocals = index + 1;
}
final int incr = operand.incr();
if ((index < 256) && ((byte) incr == incr)) {
addOpcode(Opcode.opc_iinc);
addByte(index);
addByte(incr);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_iinc);
addShort(index);
addShort(incr);
}
stackHeight += 0;
}
public void visit_i2l(final Instruction inst) {
addOpcode(Opcode.opc_i2l);
stackHeight++;
}
public void visit_i2f(final Instruction inst) {
addOpcode(Opcode.opc_i2f);
stackHeight += 0;
}
public void visit_i2d(final Instruction inst) {
addOpcode(Opcode.opc_i2d);
stackHeight++;
}
public void visit_l2i(final Instruction inst) {
addOpcode(Opcode.opc_l2i);
stackHeight--;
}
public void visit_l2f(final Instruction inst) {
addOpcode(Opcode.opc_l2f);
stackHeight--;
}
public void visit_l2d(final Instruction inst) {
addOpcode(Opcode.opc_l2d);
stackHeight += 0;
}
public void visit_f2i(final Instruction inst) {
addOpcode(Opcode.opc_f2i);
stackHeight += 0;
}
public void visit_f2l(final Instruction inst) {
addOpcode(Opcode.opc_f2l);
stackHeight++;
}
public void visit_f2d(final Instruction inst) {
addOpcode(Opcode.opc_f2d);
stackHeight++;
}
public void visit_d2i(final Instruction inst) {
addOpcode(Opcode.opc_d2i);
stackHeight--;
}
public void visit_d2l(final Instruction inst) {
addOpcode(Opcode.opc_d2l);
stackHeight += 0;
}
public void visit_d2f(final Instruction inst) {
addOpcode(Opcode.opc_d2f);
stackHeight--;
}
public void visit_i2b(final Instruction inst) {
addOpcode(Opcode.opc_i2b);
stackHeight += 0;
}
public void visit_i2c(final Instruction inst) {
addOpcode(Opcode.opc_i2c);
stackHeight += 0;
}
public void visit_i2s(final Instruction inst) {
addOpcode(Opcode.opc_i2s);
stackHeight += 0;
}
public void visit_lcmp(final Instruction inst) {
addOpcode(Opcode.opc_lcmp);
stackHeight -= 3;
}
public void visit_fcmpl(final Instruction inst) {
addOpcode(Opcode.opc_fcmpl);
stackHeight--;
}
public void visit_fcmpg(final Instruction inst) {
addOpcode(Opcode.opc_fcmpg);
stackHeight--;
}
public void visit_dcmpl(final Instruction inst) {
addOpcode(Opcode.opc_dcmpl);
stackHeight -= 3;
}
public void visit_dcmpg(final Instruction inst) {
addOpcode(Opcode.opc_dcmpg);
stackHeight -= 3;
}
/*
* Handle long branches.
*/
public void visit_ifeq(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_ifne);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_ifeq);
addBranch((Label) inst.operand());
}
stackHeight--;
}
public void visit_ifne(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_ifeq);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_ifne);
addBranch((Label) inst.operand());
}
stackHeight--;
}
public void visit_iflt(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_ifge);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_iflt);
addBranch((Label) inst.operand());
}
stackHeight--;
}
public void visit_ifge(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_iflt);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_ifge);
addBranch((Label) inst.operand());
}
stackHeight--;
}
public void visit_ifgt(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_ifle);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_ifgt);
addBranch((Label) inst.operand());
}
stackHeight--;
}
public void visit_ifle(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_ifgt);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_ifle);
addBranch((Label) inst.operand());
}
stackHeight--;
}
public void visit_if_icmpeq(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_if_icmpne);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_if_icmpeq);
addBranch((Label) inst.operand());
}
stackHeight -= 2;
}
public void visit_if_icmpne(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_if_icmpeq);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_if_icmpne);
addBranch((Label) inst.operand());
}
stackHeight -= 2;
}
public void visit_if_icmplt(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_if_icmpge);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_if_icmplt);
addBranch((Label) inst.operand());
}
stackHeight -= 2;
}
public void visit_if_icmpge(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_if_icmplt);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_if_icmpge);
addBranch((Label) inst.operand());
}
stackHeight -= 2;
}
public void visit_if_icmpgt(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_if_icmple);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_if_icmpgt);
addBranch((Label) inst.operand());
}
stackHeight -= 2;
}
public void visit_if_icmple(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_if_icmpgt);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_if_icmple);
addBranch((Label) inst.operand());
}
stackHeight -= 2;
}
public void visit_if_acmpeq(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_if_acmpne);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_if_acmpeq);
addBranch((Label) inst.operand());
}
stackHeight -= 2;
}
public void visit_if_acmpne(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_if_acmpeq);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_if_acmpne);
addBranch((Label) inst.operand());
}
stackHeight -= 2;
}
public void visit_goto(final Instruction inst) {
if (longBranch) {
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
} else {
addOpcode(Opcode.opc_goto);
addBranch((Label) inst.operand());
}
stackHeight += 0;
}
public void visit_jsr(final Instruction inst) {
if (longBranch) {
addOpcode(Opcode.opc_jsr_w);
addLongBranch((Label) inst.operand());
} else {
addOpcode(Opcode.opc_jsr);
addBranch((Label) inst.operand());
}
stackHeight++;
}
public void visit_ret(final Instruction inst) {
final int index = ((LocalVariable) inst.operand()).index();
if (index + 1 > maxLocals) {
maxLocals = index + 1;
}
if (index < 256) {
addOpcode(Opcode.opc_ret);
addByte(index);
} else {
addOpcode(Opcode.opc_wide);
addByte(Opcode.opc_ret);
addShort(index);
}
stackHeight += 0;
}
public void visit_switch(final Instruction inst) {
final Switch sw = (Switch) inst.operand();
final int[] values = sw.values();
final Label[] targets = sw.targets();
if (values.length == 0) {
if (longBranch) {
addOpcode(Opcode.opc_pop); // Pop switch "index" off stack
addOpcode(Opcode.opc_goto_w);
addLongBranch(sw.defaultTarget());
} else {
addOpcode(Opcode.opc_pop); // Pop switch "index" off stack
addOpcode(Opcode.opc_goto);
addBranch(sw.defaultTarget());
}
} else if (sw.hasContiguousValues()) {
addOpcode(Opcode.opc_tableswitch);
addLongBranch(sw.defaultTarget());
addInt(values[0]);
addInt(values[values.length - 1]);
for (int i = 0; i < targets.length; i++) {
addLongBranch(targets[i]);
}
} else {
addOpcode(Opcode.opc_lookupswitch);
addLongBranch(sw.defaultTarget());
addInt(values.length);
for (int i = 0; i < targets.length; i++) {
addInt(values[i]);
addLongBranch(targets[i]);
}
}
stackHeight--;
}
public void visit_ireturn(final Instruction inst) {
addOpcode(Opcode.opc_ireturn);
stackHeight = 0;
}
public void visit_lreturn(final Instruction inst) {
addOpcode(Opcode.opc_lreturn);
stackHeight = 0;
}
public void visit_freturn(final Instruction inst) {
addOpcode(Opcode.opc_freturn);
stackHeight = 0;
}
public void visit_dreturn(final Instruction inst) {
addOpcode(Opcode.opc_dreturn);
stackHeight = 0;
}
public void visit_areturn(final Instruction inst) {
addOpcode(Opcode.opc_areturn);
stackHeight = 0;
}
public void visit_return(final Instruction inst) {
addOpcode(Opcode.opc_return);
stackHeight = 0;
}
public void visit_getstatic(final Instruction inst) {
final int index = constants.addConstant(Constant.FIELD_REF, inst
.operand());
addOpcode(Opcode.opc_getstatic);
addShort(index);
final Type type = ((MemberRef) inst.operand()).nameAndType().type();
stackHeight += type.stackHeight();
}
public void visit_putstatic(final Instruction inst) {
final int index = constants.addConstant(Constant.FIELD_REF, inst
.operand());
addOpcode(Opcode.opc_putstatic);
addShort(index);
final Type type = ((MemberRef) inst.operand()).nameAndType().type();
stackHeight -= type.stackHeight();
}
public void visit_putstatic_nowb(final Instruction inst) {
final int index = constants.addConstant(Constant.FIELD_REF, inst
.operand());
addOpcode(Opcode.opc_putstatic_nowb);
addShort(index);
final Type type = ((MemberRef) inst.operand()).nameAndType().type();
stackHeight -= type.stackHeight();
}
public void visit_getfield(final Instruction inst) {
final int index = constants.addConstant(Constant.FIELD_REF, inst
.operand());
addOpcode(Opcode.opc_getfield);
addShort(index);
final Type type = ((MemberRef) inst.operand()).nameAndType().type();
stackHeight += type.stackHeight() - 1;
}
public void visit_putfield(final Instruction inst) {
final int index = constants.addConstant(Constant.FIELD_REF, inst
.operand());
addOpcode(Opcode.opc_putfield);
addShort(index);
final Type type = ((MemberRef) inst.operand()).nameAndType().type();
stackHeight -= type.stackHeight() + 1;
}
public void visit_putfield_nowb(final Instruction inst) {
final int index = constants.addConstant(Constant.FIELD_REF, inst
.operand());
addOpcode(Opcode.opc_putfield_nowb);
addShort(index);
final Type type = ((MemberRef) inst.operand()).nameAndType().type();
stackHeight -= type.stackHeight() + 1;
}
public void visit_invokevirtual(final Instruction inst) {
final int index = constants.addConstant(Constant.METHOD_REF, inst
.operand());
addOpcode(Opcode.opc_invokevirtual);
addShort(index);
final MemberRef method = (MemberRef) inst.operand();
final Type type = method.nameAndType().type();
stackHeight += type.returnType().stackHeight() - type.stackHeight() - 1;
}
public void visit_invokespecial(final Instruction inst) {
final int index = constants.addConstant(Constant.METHOD_REF, inst
.operand());
addOpcode(Opcode.opc_invokespecial);
addShort(index);
final MemberRef method = (MemberRef) inst.operand();
final Type type = method.nameAndType().type();
stackHeight += type.returnType().stackHeight() - type.stackHeight() - 1;
}
public void visit_invokestatic(final Instruction inst) {
final int index = constants.addConstant(Constant.METHOD_REF, inst
.operand());
addOpcode(Opcode.opc_invokestatic);
addShort(index);
final MemberRef method = (MemberRef) inst.operand();
final Type type = method.nameAndType().type();
Assert.isTrue(type.isMethod(),
"Trying to invoke a type that is not a method: " + method);
stackHeight += type.returnType().stackHeight() - type.stackHeight();
}
public void visit_invokeinterface(final Instruction inst) {
final int index = constants.addConstant(Constant.INTERFACE_METHOD_REF,
inst.operand());
final MemberRef method = (MemberRef) constants.constantAt(index);
final Type type = method.nameAndType().type();
addOpcode(Opcode.opc_invokeinterface);
addShort(index);
addByte(type.stackHeight() + 1);
addByte(0);
stackHeight += type.returnType().stackHeight() - type.stackHeight() - 1;
}
public void visit_new(final Instruction inst) {
final int index = constants.addConstant(Constant.CLASS, inst.operand());
addOpcode(Opcode.opc_new);
addShort(index);
stackHeight++;
}
public void visit_newarray(final Instruction inst) {
final Type type = (Type) inst.operand();
if (type.isReference()) {
final int index = constants.addConstant(Constant.CLASS, type);
addOpcode(Opcode.opc_anewarray);
addShort(index);
} else {
addOpcode(Opcode.opc_newarray);
addByte(type.typeCode());
}
stackHeight += 0;
}
public void visit_arraylength(final Instruction inst) {
addOpcode(Opcode.opc_arraylength);
stackHeight += 0;
}
public void visit_athrow(final Instruction inst) {
addOpcode(Opcode.opc_athrow);
stackHeight = 0;
}
public void visit_checkcast(final Instruction inst) {
final int index = constants.addConstant(Constant.CLASS, inst.operand());
addOpcode(Opcode.opc_checkcast);
addShort(index);
stackHeight += 0;
}
public void visit_instanceof(final Instruction inst) {
final int index = constants.addConstant(Constant.CLASS, inst.operand());
addOpcode(Opcode.opc_instanceof);
addShort(index);
stackHeight += 0;
}
public void visit_monitorenter(final Instruction inst) {
addOpcode(Opcode.opc_monitorenter);
stackHeight--;
}
public void visit_monitorexit(final Instruction inst) {
addOpcode(Opcode.opc_monitorexit);
stackHeight--;
}
public void visit_multianewarray(final Instruction inst) {
final MultiArrayOperand operand = (MultiArrayOperand) inst.operand();
final Type type = operand.type();
final int dim = operand.dimensions();
final int index = constants.addConstant(Constant.CLASS, type);
addOpcode(Opcode.opc_multianewarray);
addShort(index);
addByte(dim);
stackHeight += 1 - dim;
}
public void visit_ifnull(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_ifnonnull);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_ifnull);
addBranch((Label) inst.operand());
}
stackHeight--;
}
public void visit_ifnonnull(final Instruction inst) {
if (longBranch) {
final Label tmp = method.newLabel();
addOpcode(Opcode.opc_ifnull);
addBranch(tmp);
addOpcode(Opcode.opc_goto_w);
addLongBranch((Label) inst.operand());
addLabel(tmp);
} else {
addOpcode(Opcode.opc_ifnonnull);
addBranch((Label) inst.operand());
}
stackHeight--;
}
public void visit_rc(final Instruction inst) {
final Integer operand = (Integer) inst.operand();
addOpcode(Opcode.opc_rc);
addByte(operand.intValue());
stackHeight += 0;
}
public void visit_aswizzle(final Instruction inst) {
addOpcode(Opcode.opc_aswizzle);
stackHeight -= 2;
}
public void visit_aswrange(final Instruction inst) {
addOpcode(Opcode.opc_aswrange);
stackHeight -= 3;
}
public void visit_aupdate(final Instruction inst) {
final Integer operand = (Integer) inst.operand();
addOpcode(Opcode.opc_aupdate);
addByte(operand.intValue());
stackHeight += 0;
}
public void visit_supdate(final Instruction inst) {
final Integer operand = (Integer) inst.operand();
addOpcode(Opcode.opc_supdate);
addByte(operand.intValue());
stackHeight += 0;
}
/**
* Represents the height of the stack at given Label.
*/
class HeightRecord {
Label label;
int height;
public HeightRecord(final Label label, final int height) {
if (ClassEditor.DEBUG || CodeArray.DEBUG) {
System.out.println(" push " + label + " at " + height);
}
this.label = label;
this.height = height;
}
}
/**
* Used to represent the byte array.
*/
class ByteCell {
byte value;
ByteCell prev;
}
}