123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282 |
- /*
- * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999- Shigeru Chiba. 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,
- * or the Apache License Version 2.0.
- *
- * 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);
- }
- }
- }
|