aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/com/iciql/bytecode/ClassReader.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/com/iciql/bytecode/ClassReader.java')
-rw-r--r--src/main/java/com/iciql/bytecode/ClassReader.java1457
1 files changed, 1457 insertions, 0 deletions
diff --git a/src/main/java/com/iciql/bytecode/ClassReader.java b/src/main/java/com/iciql/bytecode/ClassReader.java
new file mode 100644
index 0000000..38fd2f5
--- /dev/null
+++ b/src/main/java/com/iciql/bytecode/ClassReader.java
@@ -0,0 +1,1457 @@
+/*
+ * Copyright 2004-2011 H2 Group.
+ * Copyright 2011 James Moger.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.iciql.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 com.iciql.IciqlException;
+import com.iciql.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 IciqlException("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 IciqlException("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 IciqlException(
+ // "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 IciqlException("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 IciqlException("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);
+ }
+
+}