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.
1259 lines
28 KiB
1259 lines
28 KiB
18 years ago
|
/**
|
||
|
* 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 EDU.purdue.cs.bloat.util.*;
|
||
|
|
||
|
/**
|
||
|
* <tt>Instruction</tt> represents a single instruction in the JVM. All
|
||
|
* <tt>Instruction</tt>s known their opcode. Some instructions have an
|
||
|
* operand. Operands are integers, floats, or one of the special classes that
|
||
|
* represent multiple operands such as <tt>IncOperand</tt> and <tt>Switch</tt>.
|
||
|
*
|
||
|
* @see IncOperand
|
||
|
* @see Switch
|
||
|
* @see MultiArrayOperand
|
||
|
*
|
||
|
* @author Nate Nystrom (<a
|
||
|
* href="mailto:nystrom@cs.purdue.edu">nystrom@cs.purdue.edu</a>)
|
||
|
*/
|
||
|
public class Instruction implements Opcode {
|
||
|
private Object operand;
|
||
|
|
||
|
private int opcode; // Mapped opcode
|
||
|
|
||
|
private int origOpcode; // Original (non-mapped) opcode
|
||
|
|
||
|
private boolean useSlow = false;
|
||
|
|
||
|
// Do we use a slow version when generating code?
|
||
|
|
||
|
/**
|
||
|
* Constructor.
|
||
|
*
|
||
|
* @param opcode
|
||
|
* The opcode class of the instruction.
|
||
|
*/
|
||
|
public Instruction(final int opcode) {
|
||
|
this(opcode, null);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Constructor.
|
||
|
*
|
||
|
* @param opcode
|
||
|
* The opcode class of the instruction.
|
||
|
* @param operand
|
||
|
* The operand of the instruction, or null.
|
||
|
*/
|
||
|
public Instruction(final int opcode, final Object operand) {
|
||
|
this.opcode = opcode;
|
||
|
this.origOpcode = opcode;
|
||
|
this.operand = operand;
|
||
|
Assert.isTrue(opcode == Opcode.opcXMap[opcode], "Illegal instruction: "
|
||
|
+ this);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Constructor.
|
||
|
*
|
||
|
* @param code
|
||
|
* The raw byte code array of the method.
|
||
|
* @param index
|
||
|
* This index into the byte array of the instruction.
|
||
|
* @param targets
|
||
|
* Indices of the branch targets of the instruction.
|
||
|
* @param lookups
|
||
|
* Values of the switch lookups of the instruction.
|
||
|
* @param locals
|
||
|
* The local variables defined at this index.
|
||
|
* @param constants
|
||
|
* The constant pool for the class.
|
||
|
*/
|
||
|
public Instruction(final byte[] code, final int index, final int[] targets,
|
||
|
final int[] lookups, final LocalVariable[] locals,
|
||
|
final ConstantPool constants) {
|
||
|
int i, j;
|
||
|
int incr;
|
||
|
int dim;
|
||
|
int atype;
|
||
|
Label[] t;
|
||
|
int[] v;
|
||
|
|
||
|
int opc = Instruction.toUByte(code[index]);
|
||
|
|
||
|
switch (opc) {
|
||
|
case opc_aconst_null:
|
||
|
operand = null;
|
||
|
break;
|
||
|
case opc_iconst_m1:
|
||
|
operand = new Integer(-1);
|
||
|
break;
|
||
|
case opc_iconst_0:
|
||
|
operand = new Integer(0);
|
||
|
break;
|
||
|
case opc_iconst_1:
|
||
|
operand = new Integer(1);
|
||
|
break;
|
||
|
case opc_iconst_2:
|
||
|
operand = new Integer(2);
|
||
|
break;
|
||
|
case opc_iconst_3:
|
||
|
operand = new Integer(3);
|
||
|
break;
|
||
|
case opc_iconst_4:
|
||
|
operand = new Integer(4);
|
||
|
break;
|
||
|
case opc_iconst_5:
|
||
|
operand = new Integer(5);
|
||
|
break;
|
||
|
case opc_lconst_0:
|
||
|
operand = new Long(0);
|
||
|
break;
|
||
|
case opc_lconst_1:
|
||
|
operand = new Long(1);
|
||
|
break;
|
||
|
case opc_fconst_0:
|
||
|
operand = new Float(0.0F);
|
||
|
break;
|
||
|
case opc_fconst_1:
|
||
|
operand = new Float(1.0F);
|
||
|
break;
|
||
|
case opc_fconst_2:
|
||
|
operand = new Float(2.0F);
|
||
|
break;
|
||
|
case opc_dconst_0:
|
||
|
operand = new Double(0.0);
|
||
|
break;
|
||
|
case opc_dconst_1:
|
||
|
operand = new Double(1.0);
|
||
|
break;
|
||
|
case opc_bipush:
|
||
|
operand = new Integer(code[index + 1]);
|
||
|
break;
|
||
|
case opc_sipush:
|
||
|
operand = new Integer(Instruction.toShort(code[index + 1],
|
||
|
code[index + 2]));
|
||
|
break;
|
||
|
case opc_ldc:
|
||
|
i = Instruction.toUByte(code[index + 1]);
|
||
|
operand = constants.constantAt(i);
|
||
|
break;
|
||
|
case opc_ldc_w:
|
||
|
case opc_ldc2_w:
|
||
|
i = Instruction.toUShort(code[index + 1], code[index + 2]);
|
||
|
operand = constants.constantAt(i);
|
||
|
break;
|
||
|
case opc_iload:
|
||
|
case opc_lload:
|
||
|
case opc_fload:
|
||
|
case opc_dload:
|
||
|
case opc_aload:
|
||
|
i = Instruction.toUByte(code[index + 1]);
|
||
|
operand = (i < locals.length) && (locals[i] != null) ? locals[i]
|
||
|
: new LocalVariable(i);
|
||
|
break;
|
||
|
case opc_iload_0:
|
||
|
case opc_lload_0:
|
||
|
case opc_fload_0:
|
||
|
case opc_dload_0:
|
||
|
case opc_aload_0:
|
||
|
operand = (0 < locals.length) && (locals[0] != null) ? locals[0]
|
||
|
: new LocalVariable(0);
|
||
|
break;
|
||
|
case opc_iload_1:
|
||
|
case opc_lload_1:
|
||
|
case opc_fload_1:
|
||
|
case opc_dload_1:
|
||
|
case opc_aload_1:
|
||
|
operand = (1 < locals.length) && (locals[1] != null) ? locals[1]
|
||
|
: new LocalVariable(1);
|
||
|
break;
|
||
|
case opc_iload_2:
|
||
|
case opc_lload_2:
|
||
|
case opc_fload_2:
|
||
|
case opc_dload_2:
|
||
|
case opc_aload_2:
|
||
|
operand = (2 < locals.length) && (locals[2] != null) ? locals[2]
|
||
|
: new LocalVariable(2);
|
||
|
break;
|
||
|
case opc_iload_3:
|
||
|
case opc_lload_3:
|
||
|
case opc_fload_3:
|
||
|
case opc_dload_3:
|
||
|
case opc_aload_3:
|
||
|
operand = (3 < locals.length) && (locals[3] != null) ? locals[3]
|
||
|
: new LocalVariable(3);
|
||
|
break;
|
||
|
case opc_istore:
|
||
|
case opc_lstore:
|
||
|
case opc_fstore:
|
||
|
case opc_dstore:
|
||
|
case opc_astore:
|
||
|
i = Instruction.toUByte(code[index + 1]);
|
||
|
operand = (i < locals.length) && (locals[i] != null) ? locals[i]
|
||
|
: new LocalVariable(i);
|
||
|
break;
|
||
|
case opc_istore_0:
|
||
|
case opc_lstore_0:
|
||
|
case opc_fstore_0:
|
||
|
case opc_dstore_0:
|
||
|
case opc_astore_0:
|
||
|
operand = (0 < locals.length) && (locals[0] != null) ? locals[0]
|
||
|
: new LocalVariable(0);
|
||
|
break;
|
||
|
case opc_istore_1:
|
||
|
case opc_lstore_1:
|
||
|
case opc_fstore_1:
|
||
|
case opc_dstore_1:
|
||
|
case opc_astore_1:
|
||
|
operand = (1 < locals.length) && (locals[1] != null) ? locals[1]
|
||
|
: new LocalVariable(1);
|
||
|
break;
|
||
|
case opc_istore_2:
|
||
|
case opc_lstore_2:
|
||
|
case opc_fstore_2:
|
||
|
case opc_dstore_2:
|
||
|
case opc_astore_2:
|
||
|
operand = (2 < locals.length) && (locals[2] != null) ? locals[2]
|
||
|
: new LocalVariable(2);
|
||
|
break;
|
||
|
case opc_istore_3:
|
||
|
case opc_lstore_3:
|
||
|
case opc_fstore_3:
|
||
|
case opc_dstore_3:
|
||
|
case opc_astore_3:
|
||
|
operand = (3 < locals.length) && (locals[3] != null) ? locals[3]
|
||
|
: new LocalVariable(3);
|
||
|
break;
|
||
|
case opc_iinc:
|
||
|
i = Instruction.toUByte(code[index + 1]);
|
||
|
incr = code[index + 2];
|
||
|
operand = new IncOperand(
|
||
|
(i < locals.length) && (locals[i] != null) ? locals[i]
|
||
|
: new LocalVariable(i), incr);
|
||
|
break;
|
||
|
case opc_ifeq:
|
||
|
case opc_ifne:
|
||
|
case opc_iflt:
|
||
|
case opc_ifge:
|
||
|
case opc_ifgt:
|
||
|
case opc_ifle:
|
||
|
case opc_if_icmpeq:
|
||
|
case opc_if_icmpne:
|
||
|
case opc_if_icmplt:
|
||
|
case opc_if_icmpge:
|
||
|
case opc_if_icmpgt:
|
||
|
case opc_if_icmple:
|
||
|
case opc_if_acmpeq:
|
||
|
case opc_if_acmpne:
|
||
|
Assert.isTrue(targets.length == 1, "Illegal instruction: "
|
||
|
+ Opcode.opcNames[opc]);
|
||
|
operand = new Label(targets[0]);
|
||
|
break;
|
||
|
case opc_goto:
|
||
|
case opc_jsr:
|
||
|
case opc_ifnull:
|
||
|
case opc_ifnonnull:
|
||
|
case opc_goto_w:
|
||
|
case opc_jsr_w:
|
||
|
Assert.isTrue(targets.length == 1, "Illegal instruction: "
|
||
|
+ Opcode.opcNames[opc]);
|
||
|
operand = new Label(targets[0]);
|
||
|
break;
|
||
|
case opc_ret:
|
||
|
i = Instruction.toUByte(code[index + 1]);
|
||
|
operand = (i < locals.length) && (locals[i] != null) ? locals[i]
|
||
|
: new LocalVariable(i);
|
||
|
break;
|
||
|
case opc_tableswitch:
|
||
|
// The first target is the default.
|
||
|
t = new Label[targets.length - 1];
|
||
|
v = new int[targets.length - 1];
|
||
|
for (i = 1, j = lookups[0]; i < targets.length; i++, j++) {
|
||
|
t[i - 1] = new Label(targets[i]);
|
||
|
v[i - 1] = j;
|
||
|
}
|
||
|
operand = new Switch(new Label(targets[0]), t, v);
|
||
|
break;
|
||
|
case opc_lookupswitch:
|
||
|
// The first target is the default.
|
||
|
t = new Label[targets.length - 1];
|
||
|
v = new int[targets.length - 1];
|
||
|
for (i = 1; i < targets.length; i++) {
|
||
|
t[i - 1] = new Label(targets[i]);
|
||
|
v[i - 1] = lookups[i - 1];
|
||
|
}
|
||
|
operand = new Switch(new Label(targets[0]), t, v);
|
||
|
break;
|
||
|
case opc_getstatic:
|
||
|
case opc_putstatic:
|
||
|
case opc_putstatic_nowb:
|
||
|
case opc_getfield:
|
||
|
case opc_putfield:
|
||
|
case opc_putfield_nowb:
|
||
|
case opc_invokevirtual:
|
||
|
case opc_invokespecial:
|
||
|
case opc_invokestatic:
|
||
|
case opc_invokeinterface:
|
||
|
case opc_new:
|
||
|
case opc_anewarray:
|
||
|
case opc_checkcast:
|
||
|
case opc_instanceof:
|
||
|
i = Instruction.toUShort(code[index + 1], code[index + 2]);
|
||
|
operand = constants.constantAt(i);
|
||
|
break;
|
||
|
case opc_newarray:
|
||
|
atype = code[index + 1];
|
||
|
operand = Type.getType(atype);
|
||
|
break;
|
||
|
case opc_wide:
|
||
|
opc = Instruction.toUByte(code[index + 1]);
|
||
|
switch (opc) {
|
||
|
case opc_iload:
|
||
|
case opc_fload:
|
||
|
case opc_aload:
|
||
|
case opc_lload:
|
||
|
case opc_dload:
|
||
|
case opc_istore:
|
||
|
case opc_fstore:
|
||
|
case opc_astore:
|
||
|
case opc_lstore:
|
||
|
case opc_dstore:
|
||
|
case opc_ret:
|
||
|
i = Instruction.toUShort(code[index + 2], code[index + 3]);
|
||
|
operand = (i < locals.length) && (locals[i] != null) ? locals[i]
|
||
|
: new LocalVariable(i);
|
||
|
break;
|
||
|
case opc_iinc:
|
||
|
i = Instruction.toUShort(code[index + 2], code[index + 3]);
|
||
|
incr = Instruction.toShort(code[index + 4], code[index + 5]);
|
||
|
operand = new IncOperand((i < locals.length)
|
||
|
&& (locals[i] != null) ? locals[i] : new LocalVariable(
|
||
|
i), incr);
|
||
|
break;
|
||
|
}
|
||
|
break;
|
||
|
case opc_multianewarray:
|
||
|
i = Instruction.toUShort(code[index + 1], code[index + 2]);
|
||
|
dim = Instruction.toUByte(code[index + 3]);
|
||
|
operand = new MultiArrayOperand((Type) constants.constantAt(i), dim);
|
||
|
break;
|
||
|
case opc_rc:
|
||
|
i = Instruction.toUByte(code[index + 1]);
|
||
|
operand = new Integer(i);
|
||
|
break;
|
||
|
case opc_aupdate:
|
||
|
i = Instruction.toUByte(code[index + 1]);
|
||
|
operand = new Integer(i);
|
||
|
break;
|
||
|
case opc_supdate:
|
||
|
i = Instruction.toUByte(code[index + 1]);
|
||
|
operand = new Integer(i);
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
origOpcode = opc;
|
||
|
opcode = Opcode.opcXMap[opc];
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the original (non-mapped) opcode used to create this Instruction.
|
||
|
*/
|
||
|
public int origOpcode() {
|
||
|
return (this.origOpcode);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Sets a flag that determines whether or not the "slow" version of the
|
||
|
* instruction should be generated. For example, if useSlow is true, "iload
|
||
|
* 2" is generated instead of "iload_2".
|
||
|
*/
|
||
|
public void setUseSlow(final boolean useSlow) {
|
||
|
this.useSlow = useSlow;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns whether or not the "slow" version of this instruction is
|
||
|
* generated.
|
||
|
*/
|
||
|
public boolean useSlow() {
|
||
|
return (this.useSlow);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the instruction is a load.
|
||
|
*
|
||
|
* @return true if the instruction is a load, false if not.
|
||
|
*/
|
||
|
public boolean isLoad() {
|
||
|
switch (opcode) {
|
||
|
case opc_iload:
|
||
|
case opc_lload:
|
||
|
case opc_fload:
|
||
|
case opc_dload:
|
||
|
case opc_aload:
|
||
|
case opc_iload_0:
|
||
|
case opc_lload_0:
|
||
|
case opc_fload_0:
|
||
|
case opc_dload_0:
|
||
|
case opc_aload_0:
|
||
|
case opc_iload_1:
|
||
|
case opc_lload_1:
|
||
|
case opc_fload_1:
|
||
|
case opc_dload_1:
|
||
|
case opc_aload_1:
|
||
|
case opc_iload_2:
|
||
|
case opc_lload_2:
|
||
|
case opc_fload_2:
|
||
|
case opc_dload_2:
|
||
|
case opc_aload_2:
|
||
|
case opc_iload_3:
|
||
|
case opc_lload_3:
|
||
|
case opc_fload_3:
|
||
|
case opc_dload_3:
|
||
|
case opc_aload_3:
|
||
|
return true;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the instruction is a store.
|
||
|
*
|
||
|
* @return true if the instruction is a store, false if not.
|
||
|
*/
|
||
|
public boolean isStore() {
|
||
|
switch (opcode) {
|
||
|
case opc_istore:
|
||
|
case opc_lstore:
|
||
|
case opc_fstore:
|
||
|
case opc_dstore:
|
||
|
case opc_astore:
|
||
|
case opc_istore_0:
|
||
|
case opc_lstore_0:
|
||
|
case opc_fstore_0:
|
||
|
case opc_dstore_0:
|
||
|
case opc_astore_0:
|
||
|
case opc_istore_1:
|
||
|
case opc_lstore_1:
|
||
|
case opc_fstore_1:
|
||
|
case opc_dstore_1:
|
||
|
case opc_astore_1:
|
||
|
case opc_istore_2:
|
||
|
case opc_lstore_2:
|
||
|
case opc_fstore_2:
|
||
|
case opc_dstore_2:
|
||
|
case opc_astore_2:
|
||
|
case opc_istore_3:
|
||
|
case opc_lstore_3:
|
||
|
case opc_fstore_3:
|
||
|
case opc_dstore_3:
|
||
|
case opc_astore_3:
|
||
|
return true;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the instruction is an increment.
|
||
|
*
|
||
|
* @return true if the instruction is an increment, false if not.
|
||
|
*/
|
||
|
public boolean isInc() {
|
||
|
return opcode == Opcode.opc_iinc;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the instruction is an exception throw instruction.
|
||
|
*
|
||
|
* @return true if the instruction is a throw, false if not.
|
||
|
*/
|
||
|
public boolean isThrow() {
|
||
|
return opcode == Opcode.opc_athrow;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns <tt>true</tt> if this instruction invokes a method.
|
||
|
*/
|
||
|
public boolean isInvoke() {
|
||
|
switch (opcode) {
|
||
|
case opc_invokevirtual:
|
||
|
case opc_invokespecial:
|
||
|
case opc_invokestatic:
|
||
|
case opc_invokeinterface:
|
||
|
return (true);
|
||
|
default:
|
||
|
return (false);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the instruction is a subroutine return instruction.
|
||
|
*
|
||
|
* @return true if the instruction is a ret, false if not.
|
||
|
*/
|
||
|
public boolean isRet() {
|
||
|
return opcode == Opcode.opc_ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns <tt>true</tt> if the instruction returns from a method.
|
||
|
*/
|
||
|
public boolean isReturn() {
|
||
|
switch (opcode) {
|
||
|
case opc_areturn:
|
||
|
case opc_ireturn:
|
||
|
case opc_lreturn:
|
||
|
case opc_freturn:
|
||
|
case opc_dreturn:
|
||
|
case opc_return:
|
||
|
return true;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the instruction is a switch.
|
||
|
*
|
||
|
* @return true if the instruction is a switch, false if not.
|
||
|
*/
|
||
|
public boolean isSwitch() {
|
||
|
return opcodeClass() == Opcode.opcx_switch;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the instruction is a jump.
|
||
|
*
|
||
|
* @return true if the instruction is a jump, false if not.
|
||
|
*/
|
||
|
public boolean isJump() {
|
||
|
return isConditionalJump() || isGoto();
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the instruction is a jsr.
|
||
|
*
|
||
|
* @return true if the instruction is a jsr, false if not.
|
||
|
*/
|
||
|
public boolean isJsr() {
|
||
|
return opcodeClass() == Opcode.opcx_jsr;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the instruction is a goto.
|
||
|
*
|
||
|
* @return true if the instruction is a goto, false if not.
|
||
|
*/
|
||
|
public boolean isGoto() {
|
||
|
return opcodeClass() == Opcode.opcx_goto;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Check if the instruction is a conditional jump.
|
||
|
*
|
||
|
* @return true if the instruction is a conditional jump, false if not.
|
||
|
*/
|
||
|
public boolean isConditionalJump() {
|
||
|
switch (opcode) {
|
||
|
case opc_if_icmpeq:
|
||
|
case opc_if_icmpne:
|
||
|
case opc_if_icmplt:
|
||
|
case opc_if_icmpge:
|
||
|
case opc_if_icmpgt:
|
||
|
case opc_if_icmple:
|
||
|
case opc_if_acmpeq:
|
||
|
case opc_if_acmpne:
|
||
|
case opc_ifeq:
|
||
|
case opc_ifne:
|
||
|
case opc_iflt:
|
||
|
case opc_ifge:
|
||
|
case opc_ifgt:
|
||
|
case opc_ifle:
|
||
|
case opc_ifnull:
|
||
|
case opc_ifnonnull:
|
||
|
return true;
|
||
|
default:
|
||
|
return false;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the opcode class of the instruction.
|
||
|
*
|
||
|
* @return The opcode class of the instruction.
|
||
|
*/
|
||
|
public int opcodeClass() {
|
||
|
return opcode;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the opcode class of the instruction.
|
||
|
*
|
||
|
* @param opcode
|
||
|
* The opcode class of the instruction.
|
||
|
*/
|
||
|
public void setOpcodeClass(final int opcode) {
|
||
|
this.opcode = opcode;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Set the operand of the instruction.
|
||
|
*
|
||
|
* @param operand
|
||
|
* The operand of the instruction.
|
||
|
*/
|
||
|
public void setOperand(final Object operand) {
|
||
|
this.operand = operand;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Get the operand of the instruction.
|
||
|
*
|
||
|
* @return The operand of the instruction.
|
||
|
*/
|
||
|
public Object operand() {
|
||
|
return operand;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Convert the instruction to a string.
|
||
|
*
|
||
|
* @return A string representation of the instruction.
|
||
|
*/
|
||
|
public String toString() {
|
||
|
if ((operand == null) && (opcodeClass() != Opcode.opcx_ldc)) {
|
||
|
return Opcode.opcNames[opcode];
|
||
|
} else if (operand instanceof Float) {
|
||
|
return Opcode.opcNames[opcode] + " " + operand + "F";
|
||
|
} else if (operand instanceof Long) {
|
||
|
return Opcode.opcNames[opcode] + " " + operand + "L";
|
||
|
} else if (operand instanceof String) {
|
||
|
final StringBuffer sb = new StringBuffer();
|
||
|
|
||
|
final String s = (String) operand;
|
||
|
|
||
|
for (int i = 0; i < s.length(); i++) {
|
||
|
final char c = s.charAt(i);
|
||
|
if (Character.isWhitespace(c) || ((0x20 <= c) && (c <= 0x7e))) {
|
||
|
sb.append(c);
|
||
|
} else {
|
||
|
sb.append("\\u");
|
||
|
sb.append(Integer.toHexString(c));
|
||
|
}
|
||
|
|
||
|
if (sb.length() > 50) {
|
||
|
sb.append("...");
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return Opcode.opcNames[opcode] + " \"" + sb.toString() + "\"";
|
||
|
|
||
|
} else {
|
||
|
|
||
|
return Opcode.opcNames[opcode] + " " + operand;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Utility function to join 2 bytes into an unsigned short.
|
||
|
*
|
||
|
* @param b1
|
||
|
* The upper byte.
|
||
|
* @param b2
|
||
|
* The lower byte.
|
||
|
* @return The unsigned short.
|
||
|
*/
|
||
|
protected static int toUShort(final byte b1, final byte b2) {
|
||
|
int x = (short) (Instruction.toUByte(b1) << 8)
|
||
|
| Instruction.toUByte(b2);
|
||
|
if (x < 0) {
|
||
|
x += 0x10000;
|
||
|
}
|
||
|
return x;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Utility function to join 2 bytes into an signed short.
|
||
|
*
|
||
|
* @param b1
|
||
|
* The upper byte.
|
||
|
* @param b2
|
||
|
* The lower byte.
|
||
|
* @return The signed short.
|
||
|
*/
|
||
|
protected static short toShort(final byte b1, final byte b2) {
|
||
|
return (short) ((Instruction.toUByte(b1) << 8) | Instruction
|
||
|
.toUByte(b2));
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Utility function to join 4 bytes into an signed int.
|
||
|
*
|
||
|
* @param b1
|
||
|
* The upper byte.
|
||
|
* @param b2
|
||
|
* The next-to-upper byte.
|
||
|
* @param b3
|
||
|
* The next-to-lower byte.
|
||
|
* @param b4
|
||
|
* The lower byte.
|
||
|
* @return The signed int.
|
||
|
*/
|
||
|
protected static int toInt(final byte b1, final byte b2, final byte b3,
|
||
|
final byte b4) {
|
||
|
return (Instruction.toUByte(b1) << 24)
|
||
|
| (Instruction.toUByte(b2) << 16)
|
||
|
| (Instruction.toUByte(b3) << 8) | Instruction.toUByte(b4);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Utility function to convert a byte into an unsigned byte.
|
||
|
*
|
||
|
* @param b
|
||
|
* The byte.
|
||
|
* @return The unsigned byte.
|
||
|
*/
|
||
|
protected static int toUByte(final byte b) {
|
||
|
return b < 0 ? b + 0x100 : b;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns the category of this instruction. An instruction's category is
|
||
|
* basically the width of the value the instruction places on the stack.
|
||
|
* Types <tt>long</tt> and <tt>double</tt> are Category 2. All other
|
||
|
* types are Category 1.
|
||
|
*/
|
||
|
public int category() {
|
||
|
switch (this.opcode) {
|
||
|
case opcx_lload:
|
||
|
case opcx_dload:
|
||
|
case opcx_lstore:
|
||
|
case opcx_dstore:
|
||
|
case opcx_laload:
|
||
|
case opcx_daload:
|
||
|
case opcx_lastore:
|
||
|
case opcx_dastore:
|
||
|
case opcx_ladd:
|
||
|
case opcx_dadd:
|
||
|
case opcx_lsub:
|
||
|
case opcx_dsub:
|
||
|
case opcx_lmul:
|
||
|
case opcx_dmul:
|
||
|
case opcx_ldiv:
|
||
|
case opcx_ddiv:
|
||
|
case opcx_lrem:
|
||
|
case opcx_drem:
|
||
|
case opcx_lneg:
|
||
|
case opcx_dneg:
|
||
|
case opcx_i2l:
|
||
|
case opcx_i2d:
|
||
|
case opcx_l2d:
|
||
|
case opcx_f2l:
|
||
|
case opcx_f2d:
|
||
|
case opcx_d2l:
|
||
|
case opcx_land:
|
||
|
case opcx_lor:
|
||
|
case opcx_lxor:
|
||
|
case opcx_lshl:
|
||
|
case opcx_lshr:
|
||
|
case opcx_lushr:
|
||
|
return (2);
|
||
|
|
||
|
case opcx_ldc:
|
||
|
// If we're loading a Long or Double, the category is 2.
|
||
|
if ((this.operand instanceof Long)
|
||
|
|| (this.operand instanceof Double)) {
|
||
|
return (2);
|
||
|
|
||
|
} else {
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
case opcx_invokevirtual:
|
||
|
case opcx_invokespecial:
|
||
|
case opcx_invokeinterface:
|
||
|
case opcx_invokestatic:
|
||
|
// If the return type is wide, then the category is 2.
|
||
|
final MemberRef callee = (MemberRef) this.operand;
|
||
|
if (callee.nameAndType().type().returnType().isWide()) {
|
||
|
return (2);
|
||
|
|
||
|
} else {
|
||
|
return (1);
|
||
|
}
|
||
|
|
||
|
default:
|
||
|
return (1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Big switch statement to call the appropriate method of an instruction
|
||
|
* visitor.
|
||
|
*
|
||
|
* @param visitor
|
||
|
* The instruction visitor.
|
||
|
*/
|
||
|
public void visit(final InstructionVisitor visitor) {
|
||
|
switch (opcodeClass()) {
|
||
|
case opcx_nop:
|
||
|
visitor.visit_nop(this);
|
||
|
break;
|
||
|
case opcx_ldc:
|
||
|
visitor.visit_ldc(this);
|
||
|
break;
|
||
|
case opcx_iload:
|
||
|
visitor.visit_iload(this);
|
||
|
break;
|
||
|
case opcx_lload:
|
||
|
visitor.visit_lload(this);
|
||
|
break;
|
||
|
case opcx_fload:
|
||
|
visitor.visit_fload(this);
|
||
|
break;
|
||
|
case opcx_dload:
|
||
|
visitor.visit_dload(this);
|
||
|
break;
|
||
|
case opcx_aload:
|
||
|
visitor.visit_aload(this);
|
||
|
break;
|
||
|
case opcx_iaload:
|
||
|
visitor.visit_iaload(this);
|
||
|
break;
|
||
|
case opcx_laload:
|
||
|
visitor.visit_laload(this);
|
||
|
break;
|
||
|
case opcx_faload:
|
||
|
visitor.visit_faload(this);
|
||
|
break;
|
||
|
case opcx_daload:
|
||
|
visitor.visit_daload(this);
|
||
|
break;
|
||
|
case opcx_aaload:
|
||
|
visitor.visit_aaload(this);
|
||
|
break;
|
||
|
case opcx_baload:
|
||
|
visitor.visit_baload(this);
|
||
|
break;
|
||
|
case opcx_caload:
|
||
|
visitor.visit_caload(this);
|
||
|
break;
|
||
|
case opcx_saload:
|
||
|
visitor.visit_saload(this);
|
||
|
break;
|
||
|
case opcx_istore:
|
||
|
visitor.visit_istore(this);
|
||
|
break;
|
||
|
case opcx_lstore:
|
||
|
visitor.visit_lstore(this);
|
||
|
break;
|
||
|
case opcx_fstore:
|
||
|
visitor.visit_fstore(this);
|
||
|
break;
|
||
|
case opcx_dstore:
|
||
|
visitor.visit_dstore(this);
|
||
|
break;
|
||
|
case opcx_astore:
|
||
|
visitor.visit_astore(this);
|
||
|
break;
|
||
|
case opcx_iastore:
|
||
|
visitor.visit_iastore(this);
|
||
|
break;
|
||
|
case opcx_lastore:
|
||
|
visitor.visit_lastore(this);
|
||
|
break;
|
||
|
case opcx_fastore:
|
||
|
visitor.visit_fastore(this);
|
||
|
break;
|
||
|
case opcx_dastore:
|
||
|
visitor.visit_dastore(this);
|
||
|
break;
|
||
|
case opcx_aastore:
|
||
|
visitor.visit_aastore(this);
|
||
|
break;
|
||
|
case opcx_bastore:
|
||
|
visitor.visit_bastore(this);
|
||
|
break;
|
||
|
case opcx_castore:
|
||
|
visitor.visit_castore(this);
|
||
|
break;
|
||
|
case opcx_sastore:
|
||
|
visitor.visit_sastore(this);
|
||
|
break;
|
||
|
case opcx_pop:
|
||
|
visitor.visit_pop(this);
|
||
|
break;
|
||
|
case opcx_pop2:
|
||
|
visitor.visit_pop2(this);
|
||
|
break;
|
||
|
case opcx_dup:
|
||
|
visitor.visit_dup(this);
|
||
|
break;
|
||
|
case opcx_dup_x1:
|
||
|
visitor.visit_dup_x1(this);
|
||
|
break;
|
||
|
case opcx_dup_x2:
|
||
|
visitor.visit_dup_x2(this);
|
||
|
break;
|
||
|
case opcx_dup2:
|
||
|
visitor.visit_dup2(this);
|
||
|
break;
|
||
|
case opcx_dup2_x1:
|
||
|
visitor.visit_dup2_x1(this);
|
||
|
break;
|
||
|
case opcx_dup2_x2:
|
||
|
visitor.visit_dup2_x2(this);
|
||
|
break;
|
||
|
case opcx_swap:
|
||
|
visitor.visit_swap(this);
|
||
|
break;
|
||
|
case opcx_iadd:
|
||
|
visitor.visit_iadd(this);
|
||
|
break;
|
||
|
case opcx_ladd:
|
||
|
visitor.visit_ladd(this);
|
||
|
break;
|
||
|
case opcx_fadd:
|
||
|
visitor.visit_fadd(this);
|
||
|
break;
|
||
|
case opcx_dadd:
|
||
|
visitor.visit_dadd(this);
|
||
|
break;
|
||
|
case opcx_isub:
|
||
|
visitor.visit_isub(this);
|
||
|
break;
|
||
|
case opcx_lsub:
|
||
|
visitor.visit_lsub(this);
|
||
|
break;
|
||
|
case opcx_fsub:
|
||
|
visitor.visit_fsub(this);
|
||
|
break;
|
||
|
case opcx_dsub:
|
||
|
visitor.visit_dsub(this);
|
||
|
break;
|
||
|
case opcx_imul:
|
||
|
visitor.visit_imul(this);
|
||
|
break;
|
||
|
case opcx_lmul:
|
||
|
visitor.visit_lmul(this);
|
||
|
break;
|
||
|
case opcx_fmul:
|
||
|
visitor.visit_fmul(this);
|
||
|
break;
|
||
|
case opcx_dmul:
|
||
|
visitor.visit_dmul(this);
|
||
|
break;
|
||
|
case opcx_idiv:
|
||
|
visitor.visit_idiv(this);
|
||
|
break;
|
||
|
case opcx_ldiv:
|
||
|
visitor.visit_ldiv(this);
|
||
|
break;
|
||
|
case opcx_fdiv:
|
||
|
visitor.visit_fdiv(this);
|
||
|
break;
|
||
|
case opcx_ddiv:
|
||
|
visitor.visit_ddiv(this);
|
||
|
break;
|
||
|
case opcx_irem:
|
||
|
visitor.visit_irem(this);
|
||
|
break;
|
||
|
case opcx_lrem:
|
||
|
visitor.visit_lrem(this);
|
||
|
break;
|
||
|
case opcx_frem:
|
||
|
visitor.visit_frem(this);
|
||
|
break;
|
||
|
case opcx_drem:
|
||
|
visitor.visit_drem(this);
|
||
|
break;
|
||
|
case opcx_ineg:
|
||
|
visitor.visit_ineg(this);
|
||
|
break;
|
||
|
case opcx_lneg:
|
||
|
visitor.visit_lneg(this);
|
||
|
break;
|
||
|
case opcx_fneg:
|
||
|
visitor.visit_fneg(this);
|
||
|
break;
|
||
|
case opcx_dneg:
|
||
|
visitor.visit_dneg(this);
|
||
|
break;
|
||
|
case opcx_ishl:
|
||
|
visitor.visit_ishl(this);
|
||
|
break;
|
||
|
case opcx_lshl:
|
||
|
visitor.visit_lshl(this);
|
||
|
break;
|
||
|
case opcx_ishr:
|
||
|
visitor.visit_ishr(this);
|
||
|
break;
|
||
|
case opcx_lshr:
|
||
|
visitor.visit_lshr(this);
|
||
|
break;
|
||
|
case opcx_iushr:
|
||
|
visitor.visit_iushr(this);
|
||
|
break;
|
||
|
case opcx_lushr:
|
||
|
visitor.visit_lushr(this);
|
||
|
break;
|
||
|
case opcx_iand:
|
||
|
visitor.visit_iand(this);
|
||
|
break;
|
||
|
case opcx_land:
|
||
|
visitor.visit_land(this);
|
||
|
break;
|
||
|
case opcx_ior:
|
||
|
visitor.visit_ior(this);
|
||
|
break;
|
||
|
case opcx_lor:
|
||
|
visitor.visit_lor(this);
|
||
|
break;
|
||
|
case opcx_ixor:
|
||
|
visitor.visit_ixor(this);
|
||
|
break;
|
||
|
case opcx_lxor:
|
||
|
visitor.visit_lxor(this);
|
||
|
break;
|
||
|
case opcx_iinc:
|
||
|
visitor.visit_iinc(this);
|
||
|
break;
|
||
|
case opcx_i2l:
|
||
|
visitor.visit_i2l(this);
|
||
|
break;
|
||
|
case opcx_i2f:
|
||
|
visitor.visit_i2f(this);
|
||
|
break;
|
||
|
case opcx_i2d:
|
||
|
visitor.visit_i2d(this);
|
||
|
break;
|
||
|
case opcx_l2i:
|
||
|
visitor.visit_l2i(this);
|
||
|
break;
|
||
|
case opcx_l2f:
|
||
|
visitor.visit_l2f(this);
|
||
|
break;
|
||
|
case opcx_l2d:
|
||
|
visitor.visit_l2d(this);
|
||
|
break;
|
||
|
case opcx_f2i:
|
||
|
visitor.visit_f2i(this);
|
||
|
break;
|
||
|
case opcx_f2l:
|
||
|
visitor.visit_f2l(this);
|
||
|
break;
|
||
|
case opcx_f2d:
|
||
|
visitor.visit_f2d(this);
|
||
|
break;
|
||
|
case opcx_d2i:
|
||
|
visitor.visit_d2i(this);
|
||
|
break;
|
||
|
case opcx_d2l:
|
||
|
visitor.visit_d2l(this);
|
||
|
break;
|
||
|
case opcx_d2f:
|
||
|
visitor.visit_d2f(this);
|
||
|
break;
|
||
|
case opcx_i2b:
|
||
|
visitor.visit_i2b(this);
|
||
|
break;
|
||
|
case opcx_i2c:
|
||
|
visitor.visit_i2c(this);
|
||
|
break;
|
||
|
case opcx_i2s:
|
||
|
visitor.visit_i2s(this);
|
||
|
break;
|
||
|
case opcx_lcmp:
|
||
|
visitor.visit_lcmp(this);
|
||
|
break;
|
||
|
case opcx_fcmpl:
|
||
|
visitor.visit_fcmpl(this);
|
||
|
break;
|
||
|
case opcx_fcmpg:
|
||
|
visitor.visit_fcmpg(this);
|
||
|
break;
|
||
|
case opcx_dcmpl:
|
||
|
visitor.visit_dcmpl(this);
|
||
|
break;
|
||
|
case opcx_dcmpg:
|
||
|
visitor.visit_dcmpg(this);
|
||
|
break;
|
||
|
case opcx_ifeq:
|
||
|
visitor.visit_ifeq(this);
|
||
|
break;
|
||
|
case opcx_ifne:
|
||
|
visitor.visit_ifne(this);
|
||
|
break;
|
||
|
case opcx_iflt:
|
||
|
visitor.visit_iflt(this);
|
||
|
break;
|
||
|
case opcx_ifge:
|
||
|
visitor.visit_ifge(this);
|
||
|
break;
|
||
|
case opcx_ifgt:
|
||
|
visitor.visit_ifgt(this);
|
||
|
break;
|
||
|
case opcx_ifle:
|
||
|
visitor.visit_ifle(this);
|
||
|
break;
|
||
|
case opcx_if_icmpeq:
|
||
|
visitor.visit_if_icmpeq(this);
|
||
|
break;
|
||
|
case opcx_if_icmpne:
|
||
|
visitor.visit_if_icmpne(this);
|
||
|
break;
|
||
|
case opcx_if_icmplt:
|
||
|
visitor.visit_if_icmplt(this);
|
||
|
break;
|
||
|
case opcx_if_icmpge:
|
||
|
visitor.visit_if_icmpge(this);
|
||
|
break;
|
||
|
case opcx_if_icmpgt:
|
||
|
visitor.visit_if_icmpgt(this);
|
||
|
break;
|
||
|
case opcx_if_icmple:
|
||
|
visitor.visit_if_icmple(this);
|
||
|
break;
|
||
|
case opcx_if_acmpeq:
|
||
|
visitor.visit_if_acmpeq(this);
|
||
|
break;
|
||
|
case opcx_if_acmpne:
|
||
|
visitor.visit_if_acmpne(this);
|
||
|
break;
|
||
|
case opcx_goto:
|
||
|
visitor.visit_goto(this);
|
||
|
break;
|
||
|
case opcx_jsr:
|
||
|
visitor.visit_jsr(this);
|
||
|
break;
|
||
|
case opcx_ret:
|
||
|
visitor.visit_ret(this);
|
||
|
break;
|
||
|
case opcx_switch:
|
||
|
visitor.visit_switch(this);
|
||
|
break;
|
||
|
case opcx_ireturn:
|
||
|
visitor.visit_ireturn(this);
|
||
|
break;
|
||
|
case opcx_lreturn:
|
||
|
visitor.visit_lreturn(this);
|
||
|
break;
|
||
|
case opcx_freturn:
|
||
|
visitor.visit_freturn(this);
|
||
|
break;
|
||
|
case opcx_dreturn:
|
||
|
visitor.visit_dreturn(this);
|
||
|
break;
|
||
|
case opcx_areturn:
|
||
|
visitor.visit_areturn(this);
|
||
|
break;
|
||
|
case opcx_return:
|
||
|
visitor.visit_return(this);
|
||
|
break;
|
||
|
case opcx_getstatic:
|
||
|
visitor.visit_getstatic(this);
|
||
|
break;
|
||
|
case opcx_putstatic:
|
||
|
visitor.visit_putstatic(this);
|
||
|
break;
|
||
|
case opcx_putstatic_nowb:
|
||
|
visitor.visit_putstatic_nowb(this);
|
||
|
break;
|
||
|
case opcx_getfield:
|
||
|
visitor.visit_getfield(this);
|
||
|
break;
|
||
|
case opcx_putfield:
|
||
|
visitor.visit_putfield(this);
|
||
|
break;
|
||
|
case opcx_putfield_nowb:
|
||
|
visitor.visit_putfield_nowb(this);
|
||
|
break;
|
||
|
case opcx_invokevirtual:
|
||
|
visitor.visit_invokevirtual(this);
|
||
|
break;
|
||
|
case opcx_invokespecial:
|
||
|
visitor.visit_invokespecial(this);
|
||
|
break;
|
||
|
case opcx_invokestatic:
|
||
|
visitor.visit_invokestatic(this);
|
||
|
break;
|
||
|
case opcx_invokeinterface:
|
||
|
visitor.visit_invokeinterface(this);
|
||
|
break;
|
||
|
case opcx_new:
|
||
|
visitor.visit_new(this);
|
||
|
break;
|
||
|
case opcx_newarray:
|
||
|
visitor.visit_newarray(this);
|
||
|
break;
|
||
|
case opcx_arraylength:
|
||
|
visitor.visit_arraylength(this);
|
||
|
break;
|
||
|
case opcx_athrow:
|
||
|
visitor.visit_athrow(this);
|
||
|
break;
|
||
|
case opcx_checkcast:
|
||
|
visitor.visit_checkcast(this);
|
||
|
break;
|
||
|
case opcx_instanceof:
|
||
|
visitor.visit_instanceof(this);
|
||
|
break;
|
||
|
case opcx_monitorenter:
|
||
|
visitor.visit_monitorenter(this);
|
||
|
break;
|
||
|
case opcx_monitorexit:
|
||
|
visitor.visit_monitorexit(this);
|
||
|
break;
|
||
|
case opcx_multianewarray:
|
||
|
visitor.visit_multianewarray(this);
|
||
|
break;
|
||
|
case opcx_ifnull:
|
||
|
visitor.visit_ifnull(this);
|
||
|
break;
|
||
|
case opcx_ifnonnull:
|
||
|
visitor.visit_ifnonnull(this);
|
||
|
break;
|
||
|
case opcx_rc:
|
||
|
visitor.visit_rc(this);
|
||
|
break;
|
||
|
case opcx_aupdate:
|
||
|
visitor.visit_aupdate(this);
|
||
|
break;
|
||
|
case opcx_supdate:
|
||
|
visitor.visit_supdate(this);
|
||
|
break;
|
||
|
case opcx_aswizzle:
|
||
|
visitor.visit_aswizzle(this);
|
||
|
break;
|
||
|
case opcx_aswrange:
|
||
|
visitor.visit_aswrange(this);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|