aboutsummaryrefslogtreecommitdiff
path: root/src/main/javassist/bytecode/InstructionPrinter.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/javassist/bytecode/InstructionPrinter.java')
-rw-r--r--src/main/javassist/bytecode/InstructionPrinter.java281
1 files changed, 281 insertions, 0 deletions
diff --git a/src/main/javassist/bytecode/InstructionPrinter.java b/src/main/javassist/bytecode/InstructionPrinter.java
new file mode 100644
index 0000000..f0a20e1
--- /dev/null
+++ b/src/main/javassist/bytecode/InstructionPrinter.java
@@ -0,0 +1,281 @@
+/*
+ * Javassist, a Java-bytecode translator toolkit.
+ * Copyright (C) 1999-2007 Shigeru Chiba, and others. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. Alternatively, the contents of this file may be used under
+ * the terms of the GNU Lesser General Public License Version 2.1 or later.
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ */
+package javassist.bytecode;
+
+import java.io.PrintStream;
+
+import javassist.CtMethod;
+
+/**
+ * Simple utility class for printing the instructions of a method.
+ *
+ * @author Jason T. Greene
+ */
+public class InstructionPrinter implements Opcode {
+
+ private final static String opcodes[] = Mnemonic.OPCODE;
+ private final PrintStream stream;
+
+ public InstructionPrinter(PrintStream stream) {
+ this.stream = stream;
+ }
+
+ public static void print(CtMethod method, PrintStream stream) {
+ (new InstructionPrinter(stream)).print(method);
+ }
+
+ public void print(CtMethod method) {
+ MethodInfo info = method.getMethodInfo2();
+ ConstPool pool = info.getConstPool();
+ CodeAttribute code = info.getCodeAttribute();
+ if (code == null)
+ return;
+
+ CodeIterator iterator = code.iterator();
+ while (iterator.hasNext()) {
+ int pos;
+ try {
+ pos = iterator.next();
+ } catch (BadBytecode e) {
+ throw new RuntimeException(e);
+ }
+
+ stream.println(pos + ": " + instructionString(iterator, pos, pool));
+ }
+ }
+
+ public static String instructionString(CodeIterator iter, int pos, ConstPool pool) {
+ int opcode = iter.byteAt(pos);
+
+ if (opcode > opcodes.length || opcode < 0)
+ throw new IllegalArgumentException("Invalid opcode, opcode: " + opcode + " pos: "+ pos);
+
+ String opstring = opcodes[opcode];
+ switch (opcode) {
+ case BIPUSH:
+ return opstring + " " + iter.byteAt(pos + 1);
+ case SIPUSH:
+ return opstring + " " + iter.s16bitAt(pos + 1);
+ case LDC:
+ return opstring + " " + ldc(pool, iter.byteAt(pos + 1));
+ case LDC_W :
+ case LDC2_W :
+ return opstring + " " + ldc(pool, iter.u16bitAt(pos + 1));
+ case ILOAD:
+ case LLOAD:
+ case FLOAD:
+ case DLOAD:
+ case ALOAD:
+ case ISTORE:
+ case LSTORE:
+ case FSTORE:
+ case DSTORE:
+ case ASTORE:
+ return opstring + " " + iter.byteAt(pos + 1);
+ case IFEQ:
+ case IFGE:
+ case IFGT:
+ case IFLE:
+ case IFLT:
+ case IFNE:
+ case IFNONNULL:
+ case IFNULL:
+ case IF_ACMPEQ:
+ case IF_ACMPNE:
+ case IF_ICMPEQ:
+ case IF_ICMPGE:
+ case IF_ICMPGT:
+ case IF_ICMPLE:
+ case IF_ICMPLT:
+ case IF_ICMPNE:
+ return opstring + " " + (iter.s16bitAt(pos + 1) + pos);
+ case IINC:
+ return opstring + " " + iter.byteAt(pos + 1);
+ case GOTO:
+ case JSR:
+ return opstring + " " + (iter.s16bitAt(pos + 1) + pos);
+ case RET:
+ return opstring + " " + iter.byteAt(pos + 1);
+ case TABLESWITCH:
+ return tableSwitch(iter, pos);
+ case LOOKUPSWITCH:
+ return lookupSwitch(iter, pos);
+ case GETSTATIC:
+ case PUTSTATIC:
+ case GETFIELD:
+ case PUTFIELD:
+ return opstring + " " + fieldInfo(pool, iter.u16bitAt(pos + 1));
+ case INVOKEVIRTUAL:
+ case INVOKESPECIAL:
+ case INVOKESTATIC:
+ return opstring + " " + methodInfo(pool, iter.u16bitAt(pos + 1));
+ case INVOKEINTERFACE:
+ return opstring + " " + interfaceMethodInfo(pool, iter.u16bitAt(pos + 1));
+ case 186:
+ throw new RuntimeException("Bad opcode 186");
+ case NEW:
+ return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
+ case NEWARRAY:
+ return opstring + " " + arrayInfo(iter.byteAt(pos + 1));
+ case ANEWARRAY:
+ case CHECKCAST:
+ return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
+ case WIDE:
+ return wide(iter, pos);
+ case MULTIANEWARRAY:
+ return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1));
+ case GOTO_W:
+ case JSR_W:
+ return opstring + " " + (iter.s32bitAt(pos + 1)+ pos);
+ default:
+ return opstring;
+ }
+ }
+
+
+ private static String wide(CodeIterator iter, int pos) {
+ int opcode = iter.byteAt(pos + 1);
+ int index = iter.u16bitAt(pos + 2);
+ switch (opcode) {
+ case ILOAD:
+ case LLOAD:
+ case FLOAD:
+ case DLOAD:
+ case ALOAD:
+ case ISTORE:
+ case LSTORE:
+ case FSTORE:
+ case DSTORE:
+ case ASTORE:
+ case IINC:
+ case RET:
+ return opcodes[opcode] + " " + index;
+ default:
+ throw new RuntimeException("Invalid WIDE operand");
+ }
+ }
+
+
+ private static String arrayInfo(int type) {
+ switch (type) {
+ case T_BOOLEAN:
+ return "boolean";
+ case T_CHAR:
+ return "char";
+ case T_BYTE:
+ return "byte";
+ case T_SHORT:
+ return "short";
+ case T_INT:
+ return "int";
+ case T_LONG:
+ return "long";
+ case T_FLOAT:
+ return "float";
+ case T_DOUBLE:
+ return "double";
+ default:
+ throw new RuntimeException("Invalid array type");
+ }
+ }
+
+
+ private static String classInfo(ConstPool pool, int index) {
+ return "#" + index + " = Class " + pool.getClassInfo(index);
+ }
+
+
+ private static String interfaceMethodInfo(ConstPool pool, int index) {
+ return "#" + index + " = Method "
+ + pool.getInterfaceMethodrefClassName(index) + "."
+ + pool.getInterfaceMethodrefName(index) + "("
+ + pool.getInterfaceMethodrefType(index) + ")";
+ }
+
+ private static String methodInfo(ConstPool pool, int index) {
+ return "#" + index + " = Method "
+ + pool.getMethodrefClassName(index) + "."
+ + pool.getMethodrefName(index) + "("
+ + pool.getMethodrefType(index) + ")";
+ }
+
+
+ private static String fieldInfo(ConstPool pool, int index) {
+ return "#" + index + " = Field "
+ + pool.getFieldrefClassName(index) + "."
+ + pool.getFieldrefName(index) + "("
+ + pool.getFieldrefType(index) + ")";
+ }
+
+
+ private static String lookupSwitch(CodeIterator iter, int pos) {
+ StringBuffer buffer = new StringBuffer("lookupswitch {\n");
+ int index = (pos & ~3) + 4;
+ // default
+ buffer.append("\t\tdefault: ").append(pos + iter.s32bitAt(index)).append("\n");
+ int npairs = iter.s32bitAt(index += 4);
+ int end = npairs * 8 + (index += 4);
+
+ for (; index < end; index += 8) {
+ int match = iter.s32bitAt(index);
+ int target = iter.s32bitAt(index + 4) + pos;
+ buffer.append("\t\t").append(match).append(": ").append(target).append("\n");
+ }
+
+ buffer.setCharAt(buffer.length() - 1, '}');
+ return buffer.toString();
+ }
+
+
+ private static String tableSwitch(CodeIterator iter, int pos) {
+ StringBuffer buffer = new StringBuffer("tableswitch {\n");
+ int index = (pos & ~3) + 4;
+ // default
+ buffer.append("\t\tdefault: ").append(pos + iter.s32bitAt(index)).append("\n");
+ int low = iter.s32bitAt(index += 4);
+ int high = iter.s32bitAt(index += 4);
+ int end = (high - low + 1) * 4 + (index += 4);
+
+ // Offset table
+ for (int key = low; index < end; index += 4, key++) {
+ int target = iter.s32bitAt(index) + pos;
+ buffer.append("\t\t").append(key).append(": ").append(target).append("\n");
+ }
+
+ buffer.setCharAt(buffer.length() - 1, '}');
+ return buffer.toString();
+ }
+
+
+ private static String ldc(ConstPool pool, int index) {
+ int tag = pool.getTag(index);
+ switch (tag) {
+ case ConstPool.CONST_String:
+ return "#" + index + " = \"" + pool.getStringInfo(index) + "\"";
+ case ConstPool.CONST_Integer:
+ return "#" + index + " = int " + pool.getIntegerInfo(index);
+ case ConstPool.CONST_Float:
+ return "#" + index + " = float " + pool.getFloatInfo(index);
+ case ConstPool.CONST_Long:
+ return "#" + index + " = long " + pool.getLongInfo(index);
+ case ConstPool.CONST_Double:
+ return "#" + index + " = int " + pool.getDoubleInfo(index);
+ case ConstPool.CONST_Class:
+ return classInfo(pool, index);
+ default:
+ throw new RuntimeException("bad LDC: " + tag);
+ }
+ }
+}