/* * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License, * Version 1.0, and under the Eclipse Public License, Version 1.0 * (http://h2database.com/html/license.html). * Initial Developer: H2 Group */ package org.h2.jaqu.bytecode; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import java.util.Stack; import org.h2.jaqu.Token; /** * This class converts a method to a SQL Token by interpreting * (decompiling) the bytecode of the class. */ public class ClassReader { private static final boolean DEBUG = false; private byte[] data; private int pos; private Constant[] constantPool; private int startByteCode; private String methodName; private String convertMethodName; private Token result; private Stack<Token> stack = new Stack<Token>(); private ArrayList<Token> variables = new ArrayList<Token>(); private boolean endOfMethod; private boolean condition; private int nextPc; private Map<String, Object> fieldMap = new HashMap<String, Object>(); private static void debug(String s) { if (DEBUG) { System.out.println(s); } } public Token decompile(Object instance, Map<String, Object> fields, String method) { this.fieldMap = fields; this.convertMethodName = method; Class<?> clazz = instance.getClass(); String className = clazz.getName(); debug("class name " + className); ByteArrayOutputStream buff = new ByteArrayOutputStream(); try { InputStream in = clazz.getClassLoader().getResource(className.replace('.', '/') + ".class").openStream(); while (true) { int x = in.read(); if (x < 0) { break; } buff.write(x); } } catch (IOException e) { throw new RuntimeException("Could not read class bytecode", e); } data = buff.toByteArray(); int header = readInt(); debug("header: " + Integer.toHexString(header)); int minorVersion = readShort(); int majorVersion = readShort(); debug("version: " + majorVersion + "." + minorVersion); int constantPoolCount = readShort(); constantPool = new Constant[constantPoolCount]; for (int i = 1; i < constantPoolCount; i++) { int type = readByte(); switch(type) { case 1: constantPool[i] = ConstantString.get(readString()); break; case 3: { int x = readInt(); constantPool[i] = ConstantNumber.get(x); break; } case 4: { int x = readInt(); constantPool[i] = ConstantNumber.get("" + Float.intBitsToFloat(x), x, Constant.Type.FLOAT); break; } case 5: { long x = readLong(); constantPool[i] = ConstantNumber.get(x); i++; break; } case 6: { long x = readLong(); constantPool[i] = ConstantNumber.get("" + Double.longBitsToDouble(x), x, Constant.Type.DOUBLE); i++; break; } case 7: { int x = readShort(); constantPool[i] = ConstantNumber.get(null, x, ConstantNumber.Type.CLASS_REF); break; } case 8: { int x = readShort(); constantPool[i] = ConstantNumber.get(null, x, ConstantNumber.Type.STRING_REF); break; } case 9: { int x = readInt(); constantPool[i] = ConstantNumber.get(null, x, ConstantNumber.Type.FIELD_REF); break; } case 10: { int x = readInt(); constantPool[i] = ConstantNumber.get(null, x, ConstantNumber.Type.METHOD_REF); break; } case 11: { int x = readInt(); constantPool[i] = ConstantNumber.get(null, x, ConstantNumber.Type.INTERFACE_METHOD_REF); break; } case 12: { int x = readInt(); constantPool[i] = ConstantNumber.get(null, x, ConstantNumber.Type.NAME_AND_TYPE); break; } default: throw new RuntimeException("Unsupported constant pool tag: " + type); } } int accessFlags = readShort(); debug("access flags: " + accessFlags); int classRef = readShort(); debug("class: " + constantPool[constantPool[classRef].intValue()]); int superClassRef = readShort(); debug(" extends " + constantPool[constantPool[superClassRef].intValue()]); int interfaceCount = readShort(); for (int i = 0; i < interfaceCount; i++) { int interfaceRef = readShort(); debug(" implements " + constantPool[constantPool[interfaceRef].intValue()]); } int fieldCount = readShort(); for (int i = 0; i < fieldCount; i++) { readField(); } int methodCount = readShort(); for (int i = 0; i < methodCount; i++) { readMethod(); } readAttributes(); return result; } private void readField() { int accessFlags = readShort(); int nameIndex = readShort(); int descIndex = readShort(); debug(" " + constantPool[descIndex] + " " + constantPool[nameIndex] + " " + accessFlags); readAttributes(); } private void readMethod() { int accessFlags = readShort(); int nameIndex = readShort(); int descIndex = readShort(); String desc = constantPool[descIndex].toString(); methodName = constantPool[nameIndex].toString(); debug(" " + desc + " " + methodName + " " + accessFlags); readAttributes(); } private void readAttributes() { int attributeCount = readShort(); for (int i = 0; i < attributeCount; i++) { int attributeNameIndex = readShort(); String attributeName = constantPool[attributeNameIndex].toString(); debug(" attribute " + attributeName); int attributeLength = readInt(); int end = pos + attributeLength; if ("Code".equals(attributeName)) { readCode(); } pos = end; } } void decompile() { int maxStack = readShort(); int maxLocals = readShort(); debug("stack: " + maxStack + " locals: " + maxLocals); int codeLength = readInt(); startByteCode = pos; int end = pos + codeLength; while (pos < end) { readByteCode(); } debug(""); pos = startByteCode + codeLength; int exceptionTableLength = readShort(); pos += 2 * exceptionTableLength; readAttributes(); } private void readCode() { variables.clear(); stack.clear(); int maxStack = readShort(); int maxLocals = readShort(); debug("stack: " + maxStack + " locals: " + maxLocals); int codeLength = readInt(); startByteCode = pos; if (methodName.startsWith(convertMethodName)) { result = getResult(); } pos = startByteCode + codeLength; int exceptionTableLength = readShort(); pos += 2 * exceptionTableLength; readAttributes(); } private Token getResult() { while (true) { readByteCode(); if (endOfMethod) { return stack.pop(); } if (condition) { Token c = stack.pop(); Stack<Token> currentStack = new Stack<Token>(); currentStack.addAll(stack); ArrayList<Token> currentVariables = new ArrayList<Token>(); currentVariables.addAll(variables); int branch = nextPc; Token a = getResult(); stack = currentStack; variables = currentVariables; pos = branch + startByteCode; Token b = getResult(); if (a.equals("0") && b.equals("1")) { return c; } else if (a.equals("1") && b.equals("0")) { return Not.get(c); } else if (b.equals("0")) { return And.get(Not.get(c), a); } else if (a.equals("0")) { return And.get(c, b); } else if (b.equals("1")) { return Or.get(c, a); } else if (a.equals("1")) { return And.get(Not.get(c), b); } return CaseWhen.get(c, b, a); } if (nextPc != 0) { pos = nextPc + startByteCode; } } } private void readByteCode() { int startPos = pos - startByteCode; int opCode = readByte(); String op; endOfMethod = false; condition = false; nextPc = 0; switch(opCode) { case 0: op = "nop"; break; case 1: op = "aconst_null"; stack.push(Null.INSTANCE); break; case 2: op = "iconst_m1"; stack.push(ConstantNumber.get("-1")); break; case 3: op = "iconst_0"; stack.push(ConstantNumber.get("0")); break; case 4: op = "iconst_1"; stack.push(ConstantNumber.get("1")); break; case 5: op = "iconst_2"; stack.push(ConstantNumber.get("2")); break; case 6: op = "iconst_3"; stack.push(ConstantNumber.get("3")); break; case 7: op = "iconst_4"; stack.push(ConstantNumber.get("4")); break; case 8: op = "iconst_5"; stack.push(ConstantNumber.get("5")); break; case 9: op = "lconst_0"; stack.push(ConstantNumber.get("0")); break; case 10: op = "lconst_1"; stack.push(ConstantNumber.get("1")); break; case 11: op = "fconst_0"; stack.push(ConstantNumber.get("0.0")); break; case 12: op = "fconst_1"; stack.push(ConstantNumber.get("1.0")); break; case 13: op = "fconst_2"; stack.push(ConstantNumber.get("2.0")); break; case 14: op = "dconst_0"; stack.push(ConstantNumber.get("0.0")); break; case 15: op = "dconst_1"; stack.push(ConstantNumber.get("1.0")); break; case 16: { int x = (byte) readByte(); op = "bipush " + x; stack.push(ConstantNumber.get(x)); break; } case 17: { int x = (short) readShort(); op = "sipush " + x; stack.push(ConstantNumber.get(x)); break; } case 18: { Token s = getConstant(readByte()); op = "ldc " + s; stack.push(s); break; } case 19: { Token s = getConstant(readShort()); op = "ldc_w " + s; stack.push(s); break; } case 20: { Token s = getConstant(readShort()); op = "ldc2_w " + s; stack.push(s); break; } case 21: { int x = readByte(); op = "iload " + x; stack.push(getVariable(x)); break; } case 22: { int x = readByte(); op = "lload " + x; stack.push(getVariable(x)); break; } case 23: { int x = readByte(); op = "fload " + x; stack.push(getVariable(x)); break; } case 24: { int x = readByte(); op = "dload " + x; stack.push(getVariable(x)); break; } case 25: { int x = readByte(); op = "aload " + x; stack.push(getVariable(x)); break; } case 26: op = "iload_0"; stack.push(getVariable(0)); break; case 27: op = "iload_1"; stack.push(getVariable(1)); break; case 28: op = "iload_2"; stack.push(getVariable(2)); break; case 29: op = "iload_3"; stack.push(getVariable(3)); break; case 30: op = "lload_0"; stack.push(getVariable(0)); break; case 31: op = "lload_1"; stack.push(getVariable(1)); break; case 32: op = "lload_2"; stack.push(getVariable(2)); break; case 33: op = "lload_3"; stack.push(getVariable(3)); break; case 34: op = "fload_0"; stack.push(getVariable(0)); break; case 35: op = "fload_1"; stack.push(getVariable(1)); break; case 36: op = "fload_2"; stack.push(getVariable(2)); break; case 37: op = "fload_3"; stack.push(getVariable(3)); break; case 38: op = "dload_0"; stack.push(getVariable(0)); break; case 39: op = "dload_1"; stack.push(getVariable(1)); break; case 40: op = "dload_2"; stack.push(getVariable(2)); break; case 41: op = "dload_3"; stack.push(getVariable(3)); break; case 42: op = "aload_0"; stack.push(getVariable(0)); break; case 43: op = "aload_1"; stack.push(getVariable(1)); break; case 44: op = "aload_2"; stack.push(getVariable(2)); break; case 45: op = "aload_3"; stack.push(getVariable(3)); break; case 46: { Token index = stack.pop(); Token ref = stack.pop(); op = "iaload"; stack.push(ArrayGet.get(ref, index)); break; } case 47: { Token index = stack.pop(); Token ref = stack.pop(); op = "laload"; stack.push(ArrayGet.get(ref, index)); break; } case 48: { Token index = stack.pop(); Token ref = stack.pop(); op = "faload"; stack.push(ArrayGet.get(ref, index)); break; } case 49: { Token index = stack.pop(); Token ref = stack.pop(); op = "daload"; stack.push(ArrayGet.get(ref, index)); break; } case 50: { Token index = stack.pop(); Token ref = stack.pop(); op = "aaload"; stack.push(ArrayGet.get(ref, index)); break; } case 51: { Token index = stack.pop(); Token ref = stack.pop(); op = "baload"; stack.push(ArrayGet.get(ref, index)); break; } case 52: { Token index = stack.pop(); Token ref = stack.pop(); op = "caload"; stack.push(ArrayGet.get(ref, index)); break; } case 53: { Token index = stack.pop(); Token ref = stack.pop(); op = "saload"; stack.push(ArrayGet.get(ref, index)); break; } case 54: { int var = readByte(); op = "istore " + var; setVariable(var, stack.pop()); break; } case 55: { int var = readByte(); op = "lstore " + var; setVariable(var, stack.pop()); break; } case 56: { int var = readByte(); op = "fstore " + var; setVariable(var, stack.pop()); break; } case 57: { int var = readByte(); op = "dstore " + var; setVariable(var, stack.pop()); break; } case 58: { int var = readByte(); op = "astore " + var; setVariable(var, stack.pop()); break; } case 59: op = "istore_0"; setVariable(0, stack.pop()); break; case 60: op = "istore_1"; setVariable(1, stack.pop()); break; case 61: op = "istore_2"; setVariable(2, stack.pop()); break; case 62: op = "istore_3"; setVariable(3, stack.pop()); break; case 63: op = "lstore_0"; setVariable(0, stack.pop()); break; case 64: op = "lstore_1"; setVariable(1, stack.pop()); break; case 65: op = "lstore_2"; setVariable(2, stack.pop()); break; case 66: op = "lstore_3"; setVariable(3, stack.pop()); break; case 67: op = "fstore_0"; setVariable(0, stack.pop()); break; case 68: op = "fstore_1"; setVariable(1, stack.pop()); break; case 69: op = "fstore_2"; setVariable(2, stack.pop()); break; case 70: op = "fstore_3"; setVariable(3, stack.pop()); break; case 71: op = "dstore_0"; setVariable(0, stack.pop()); break; case 72: op = "dstore_1"; setVariable(1, stack.pop()); break; case 73: op = "dstore_2"; setVariable(2, stack.pop()); break; case 74: op = "dstore_3"; setVariable(3, stack.pop()); break; case 75: op = "astore_0"; setVariable(0, stack.pop()); break; case 76: op = "astore_1"; setVariable(1, stack.pop()); break; case 77: op = "astore_2"; setVariable(2, stack.pop()); break; case 78: op = "astore_3"; setVariable(3, stack.pop()); break; case 79: { // String value = stack.pop(); // String index = stack.pop(); // String ref = stack.pop(); op = "iastore"; // TODO side effect - not supported break; } case 80: op = "lastore"; // TODO side effect - not supported break; case 81: op = "fastore"; // TODO side effect - not supported break; case 82: op = "dastore"; // TODO side effect - not supported break; case 83: op = "aastore"; // TODO side effect - not supported break; case 84: op = "bastore"; // TODO side effect - not supported break; case 85: op = "castore"; // TODO side effect - not supported break; case 86: op = "sastore"; // TODO side effect - not supported break; case 87: op = "pop"; stack.pop(); break; case 88: op = "pop2"; // TODO currently we don't know the stack types stack.pop(); stack.pop(); break; case 89: { op = "dup"; Token x = stack.pop(); stack.push(x); stack.push(x); break; } case 90: { op = "dup_x1"; Token a = stack.pop(); Token b = stack.pop(); stack.push(a); stack.push(b); stack.push(a); break; } case 91: { // TODO currently we don't know the stack types op = "dup_x2"; Token a = stack.pop(); Token b = stack.pop(); Token c = stack.pop(); stack.push(a); stack.push(c); stack.push(b); stack.push(a); break; } case 92: { // TODO currently we don't know the stack types op = "dup2"; Token a = stack.pop(); Token b = stack.pop(); stack.push(b); stack.push(a); stack.push(b); stack.push(a); break; } case 93: { // TODO currently we don't know the stack types op = "dup2_x1"; Token a = stack.pop(); Token b = stack.pop(); Token c = stack.pop(); stack.push(b); stack.push(a); stack.push(c); stack.push(b); stack.push(a); break; } case 94: { // TODO currently we don't know the stack types op = "dup2_x2"; Token a = stack.pop(); Token b = stack.pop(); Token c = stack.pop(); Token d = stack.pop(); stack.push(b); stack.push(a); stack.push(d); stack.push(c); stack.push(b); stack.push(a); break; } case 95: { op = "swap"; Token a = stack.pop(); Token b = stack.pop(); stack.push(a); stack.push(b); break; } case 96: { Token b = stack.pop(); Token a = stack.pop(); op = "iadd"; stack.push(Operation.get(a, Operation.Type.ADD, b)); break; } case 97: { Token b = stack.pop(); Token a = stack.pop(); op = "ladd"; stack.push(Operation.get(a, Operation.Type.ADD, b)); break; } case 98: { Token b = stack.pop(); Token a = stack.pop(); op = "fadd"; stack.push(Operation.get(a, Operation.Type.ADD, b)); break; } case 99: { Token b = stack.pop(); Token a = stack.pop(); op = "dadd"; stack.push(Operation.get(a, Operation.Type.ADD, b)); break; } case 100: { Token b = stack.pop(); Token a = stack.pop(); op = "isub"; stack.push(Operation.get(a, Operation.Type.SUBTRACT, b)); break; } case 101: { Token b = stack.pop(); Token a = stack.pop(); op = "lsub"; stack.push(Operation.get(a, Operation.Type.SUBTRACT, b)); break; } case 102: { Token b = stack.pop(); Token a = stack.pop(); op = "fsub"; stack.push(Operation.get(a, Operation.Type.SUBTRACT, b)); break; } case 103: { Token b = stack.pop(); Token a = stack.pop(); op = "dsub"; stack.push(Operation.get(a, Operation.Type.SUBTRACT, b)); break; } case 104: { Token b = stack.pop(); Token a = stack.pop(); op = "imul"; stack.push(Operation.get(a, Operation.Type.MULTIPLY, b)); break; } case 105: { Token b = stack.pop(); Token a = stack.pop(); op = "lmul"; stack.push(Operation.get(a, Operation.Type.MULTIPLY, b)); break; } case 106: { Token b = stack.pop(); Token a = stack.pop(); op = "fmul"; stack.push(Operation.get(a, Operation.Type.MULTIPLY, b)); break; } case 107: { Token b = stack.pop(); Token a = stack.pop(); op = "dmul"; stack.push(Operation.get(a, Operation.Type.MULTIPLY, b)); break; } case 108: { Token b = stack.pop(); Token a = stack.pop(); op = "idiv"; stack.push(Operation.get(a, Operation.Type.DIVIDE, b)); break; } case 109: { Token b = stack.pop(); Token a = stack.pop(); op = "ldiv"; stack.push(Operation.get(a, Operation.Type.DIVIDE, b)); break; } case 110: { Token b = stack.pop(); Token a = stack.pop(); op = "fdiv"; stack.push(Operation.get(a, Operation.Type.DIVIDE, b)); break; } case 111: { Token b = stack.pop(); Token a = stack.pop(); op = "ddiv"; stack.push(Operation.get(a, Operation.Type.DIVIDE, b)); break; } case 112: { Token b = stack.pop(); Token a = stack.pop(); op = "irem"; stack.push(Operation.get(a, Operation.Type.MOD, b)); break; } case 113: { Token b = stack.pop(); Token a = stack.pop(); op = "lrem"; stack.push(Operation.get(a, Operation.Type.MOD, b)); break; } case 114: { Token b = stack.pop(); Token a = stack.pop(); op = "frem"; stack.push(Operation.get(a, Operation.Type.MOD, b)); break; } case 115: { Token b = stack.pop(); Token a = stack.pop(); op = "drem"; stack.push(Operation.get(a, Operation.Type.MOD, b)); break; } // case 116: // op = "ineg"; // break; // case 117: // op = "lneg"; // break; // case 118: // op = "fneg"; // break; // case 119: // op = "dneg"; // break; // case 120: // op = "ishl"; // break; // case 121: // op = "lshl"; // break; // case 122: // op = "ishr"; // break; // case 123: // op = "lshr"; // break; // case 124: // op = "iushr"; // break; // case 125: // op = "lushr"; // break; // case 126: // op = "iand"; // break; // case 127: // op = "land"; // break; // case 128: // op = "ior"; // break; // case 129: // op = "lor"; // break; // case 130: // op = "ixor"; // break; // case 131: // op = "lxor"; // break; // case 132: { // int var = readByte(); // int off = (byte) readByte(); // op = "iinc " + var + " " + off; // break; // } // case 133: // op = "i2l"; // break; // case 134: // op = "i2f"; // break; // case 135: // op = "i2d"; // break; // case 136: // op = "l2i"; // break; // case 137: // op = "l2f"; // break; // case 138: // op = "l2d"; // break; // case 139: // op = "f2i"; // break; // case 140: // op = "f2l"; // break; // case 141: // op = "f2d"; // break; // case 142: // op = "d2i"; // break; // case 143: // op = "d2l"; // break; // case 144: // op = "d2f"; // break; // case 145: // op = "i2b"; // break; // case 146: // op = "i2c"; // break; // case 147: // op = "i2s"; // break; case 148: { Token b = stack.pop(), a = stack.pop(); stack.push(new Function("SIGN", Operation.get(a, Operation.Type.SUBTRACT, b))); op = "lcmp"; break; } // case 149: // op = "fcmpl"; // break; // case 150: // op = "fcmpg"; // break; // case 151: // op = "dcmpl"; // break; // case 152: // op = "dcmpg"; // break; case 153: condition = true; nextPc = getAbsolutePos(pos, readShort()); stack.push(Operation.get(stack.pop(), Operation.Type.EQUALS, ConstantNumber.get(0))); op = "ifeq " + nextPc; break; case 154: condition = true; nextPc = getAbsolutePos(pos, readShort()); stack.push(Operation.get(stack.pop(), Operation.Type.NOT_EQUALS, ConstantNumber.get(0))); op = "ifne " + nextPc; break; case 155: condition = true; nextPc = getAbsolutePos(pos, readShort()); stack.push(Operation.get(stack.pop(), Operation.Type.SMALLER, ConstantNumber.get(0))); op = "iflt " + nextPc; break; case 156: condition = true; nextPc = getAbsolutePos(pos, readShort()); stack.push(Operation.get(stack.pop(), Operation.Type.BIGGER_EQUALS, ConstantNumber.get(0))); op = "ifge " + nextPc; break; case 157: condition = true; nextPc = getAbsolutePos(pos, readShort()); stack.push(Operation.get(stack.pop(), Operation.Type.BIGGER, ConstantNumber.get(0))); op = "ifgt " + nextPc; break; case 158: condition = true; nextPc = getAbsolutePos(pos, readShort()); stack.push(Operation.get(stack.pop(), Operation.Type.SMALLER_EQUALS, ConstantNumber.get(0))); op = "ifle " + nextPc; break; case 159: { condition = true; nextPc = getAbsolutePos(pos, readShort()); Token b = stack.pop(), a = stack.pop(); stack.push(Operation.get(a, Operation.Type.EQUALS, b)); op = "if_icmpeq " + nextPc; break; } case 160: { condition = true; nextPc = getAbsolutePos(pos, readShort()); Token b = stack.pop(), a = stack.pop(); stack.push(Operation.get(a, Operation.Type.NOT_EQUALS, b)); op = "if_icmpne " + nextPc; break; } case 161: { condition = true; nextPc = getAbsolutePos(pos, readShort()); Token b = stack.pop(), a = stack.pop(); stack.push(Operation.get(a, Operation.Type.SMALLER, b)); op = "if_icmplt " + nextPc; break; } case 162: { condition = true; nextPc = getAbsolutePos(pos, readShort()); Token b = stack.pop(), a = stack.pop(); stack.push(Operation.get(a, Operation.Type.BIGGER_EQUALS, b)); op = "if_icmpge " + nextPc; break; } case 163: { condition = true; nextPc = getAbsolutePos(pos, readShort()); Token b = stack.pop(), a = stack.pop(); stack.push(Operation.get(a, Operation.Type.BIGGER, b)); op = "if_icmpgt " + nextPc; break; } case 164: { condition = true; nextPc = getAbsolutePos(pos, readShort()); Token b = stack.pop(), a = stack.pop(); stack.push(Operation.get(a, Operation.Type.SMALLER_EQUALS, b)); op = "if_icmple " + nextPc; break; } case 165: { condition = true; nextPc = getAbsolutePos(pos, readShort()); Token b = stack.pop(), a = stack.pop(); stack.push(Operation.get(a, Operation.Type.EQUALS, b)); op = "if_acmpeq " + nextPc; break; } case 166: { condition = true; nextPc = getAbsolutePos(pos, readShort()); Token b = stack.pop(), a = stack.pop(); stack.push(Operation.get(a, Operation.Type.NOT_EQUALS, b)); op = "if_acmpne " + nextPc; break; } case 167: nextPc = getAbsolutePos(pos, readShort()); op = "goto " + nextPc; break; // case 168: // // TODO not supported yet // op = "jsr " + getAbsolutePos(pos, readShort()); // break; // case 169: // // TODO not supported yet // op = "ret " + readByte(); // break; // case 170: { // int start = pos; // pos += 4 - ((pos - startByteCode) & 3); // int def = readInt(); // int low = readInt(), high = readInt(); // int n = high - low + 1; // op = "tableswitch default:" + getAbsolutePos(start, def); // StringBuilder buff = new StringBuilder(); // for (int i = 0; i < n; i++) { // buff.append(' ').append(low++). // append(":"). // append(getAbsolutePos(start, readInt())); // } // op += buff.toString(); // // pos += n * 4; // break; // } // case 171: { // int start = pos; // pos += 4 - ((pos - startByteCode) & 3); // int def = readInt(); // int n = readInt(); // op = "lookupswitch default:" + getAbsolutePos(start, def); // StringBuilder buff = new StringBuilder(); // for (int i = 0; i < n; i++) { // buff.append(' '). // append(readInt()). // append(":"). // append(getAbsolutePos(start, readInt())); // } // op += buff.toString(); // // pos += n * 8; // break; // } case 172: op = "ireturn"; endOfMethod = true; break; case 173: op = "lreturn"; endOfMethod = true; break; case 174: op = "freturn"; endOfMethod = true; break; case 175: op = "dreturn"; endOfMethod = true; break; case 176: op = "areturn"; endOfMethod = true; break; case 177: op = "return"; // no value returned stack.push(null); endOfMethod = true; break; // case 178: // op = "getstatic " + getField(readShort()); // break; // case 179: // op = "putstatic " + getField(readShort()); // break; case 180: { String field = getField(readShort()); Token p = stack.pop(); String s = p + "." + field.substring(field.lastIndexOf('.') + 1, field.indexOf(' ')); if (s.startsWith("this.")) { s = s.substring(5); } stack.push(Variable.get(s, fieldMap.get(s))); op = "getfield " + field; break; } // case 181: // op = "putfield " + getField(readShort()); // break; case 182: { String method = getMethod(readShort()); op = "invokevirtual " + method; if (method.equals("java/lang/String.equals (Ljava/lang/Object;)Z")) { Token a = stack.pop(); Token b = stack.pop(); stack.push(Operation.get(a, Operation.Type.EQUALS, b)); } else if (method.equals("java/lang/Integer.intValue ()I")) { // ignore } else if (method.equals("java/lang/Long.longValue ()J")) { // ignore } break; } case 183: { String method = getMethod(readShort()); op = "invokespecial " + method; break; } case 184: op = "invokestatic " + getMethod(readShort()); break; // case 185: { // int methodRef = readShort(); // readByte(); // readByte(); // op = "invokeinterface " + getMethod(methodRef); // break; // } case 187: { String className = constantPool[constantPool[readShort()].intValue()].toString(); op = "new " + className; break; } // case 188: // op = "newarray " + readByte(); // break; // case 189: // op = "anewarray " + cpString[readShort()]; // break; // case 190: // op = "arraylength"; // break; // case 191: // op = "athrow"; // break; // case 192: // op = "checkcast " + cpString[readShort()]; // break; // case 193: // op = "instanceof " + cpString[readShort()]; // break; // case 194: // op = "monitorenter"; // break; // case 195: // op = "monitorexit"; // break; // case 196: { // opCode = readByte(); // switch (opCode) { // case 21: // op = "wide iload " + readShort(); // break; // case 22: // op = "wide lload " + readShort(); // break; // case 23: // op = "wide fload " + readShort(); // break; // case 24: // op = "wide dload " + readShort(); // break; // case 25: // op = "wide aload " + readShort(); // break; // case 54: // op = "wide istore " + readShort(); // break; // case 55: // op = "wide lstore " + readShort(); // break; // case 56: // op = "wide fstore " + readShort(); // break; // case 57: // op = "wide dstore " + readShort(); // break; // case 58: // op = "wide astore " + readShort(); // break; // case 132: { // int var = readShort(); // int off = (short) readShort(); // op = "wide iinc " + var + " " + off; // break; // } // case 169: // op = "wide ret " + readShort(); // break; // default: // throw new RuntimeException( // "Unsupported wide opCode " + opCode); // } // break; // } // case 197: // op = "multianewarray " + cpString[readShort()] + " " + readByte(); // break; // case 198: { // condition = true; // nextPc = getAbsolutePos(pos, readShort()); // Token a = stack.pop(); // stack.push("(" + a + " IS NULL)"); // op = "ifnull " + nextPc; // break; // } // case 199: { // condition = true; // nextPc = getAbsolutePos(pos, readShort()); // Token a = stack.pop(); // stack.push("(" + a + " IS NOT NULL)"); // op = "ifnonnull " + nextPc; // break; // } case 200: op = "goto_w " + getAbsolutePos(pos, readInt()); break; case 201: op = "jsr_w " + getAbsolutePos(pos, readInt()); break; default: throw new RuntimeException("Unsupported opCode " + opCode); } debug(" " + startPos + ": " + op); } private void setVariable(int x, Token value) { while (x >= variables.size()) { variables.add(Variable.get("p" + variables.size(), null)); } variables.set(x, value); } private Token getVariable(int x) { if (x == 0) { return Variable.THIS; } while (x >= variables.size()) { variables.add(Variable.get("p" + variables.size(), null)); } return variables.get(x); } private String getField(int fieldRef) { int field = constantPool[fieldRef].intValue(); int classIndex = field >>> 16; int nameAndType = constantPool[field & 0xffff].intValue(); String className = constantPool[constantPool[classIndex].intValue()] + "." + constantPool[nameAndType >>> 16] + " " + constantPool[nameAndType & 0xffff]; return className; } private String getMethod(int methodRef) { int method = constantPool[methodRef].intValue(); int classIndex = method >>> 16; int nameAndType = constantPool[method & 0xffff].intValue(); String className = constantPool[constantPool[classIndex].intValue()] + "." + constantPool[nameAndType >>> 16] + " " + constantPool[nameAndType & 0xffff]; return className; } private Constant getConstant(int constantRef) { Constant c = constantPool[constantRef]; switch (c.getType()) { case INT: case FLOAT: case DOUBLE: case LONG: return c; case STRING_REF: return constantPool[c.intValue()]; default: throw new RuntimeException("Not a constant: " + constantRef); } } private String readString() { int size = readShort(); byte[] buff = data; int p = pos, end = p + size; char[] chars = new char[size]; int j = 0; for (; p < end; j++) { int x = buff[p++] & 0xff; if (x < 0x80) { chars[j] = (char) x; } else if (x >= 0xe0) { chars[j] = (char) (((x & 0xf) << 12) + ((buff[p++] & 0x3f) << 6) + (buff[p++] & 0x3f)); } else { chars[j] = (char) (((x & 0x1f) << 6) + (buff[p++] & 0x3f)); } } pos = p; return new String(chars, 0, j); } private int getAbsolutePos(int start, int offset) { return start - startByteCode - 1 + (short) offset; } private int readByte() { return data[pos++] & 0xff; } private int readShort() { byte[] buff = data; return ((buff[pos++] & 0xff) << 8) + (buff[pos++] & 0xff); } private int readInt() { byte[] buff = data; return (buff[pos++] << 24) + ((buff[pos++] & 0xff) << 16) + ((buff[pos++] & 0xff) << 8) + (buff[pos++] & 0xff); } private long readLong() { return ((long) (readInt()) << 32) + (readInt() & 0xffffffffL); } }