提交 fb7066ce authored 作者: Thomas Mueller's avatar Thomas Mueller

JaQu: the decompiler has been improved.

上级 76feb2b3
...@@ -94,6 +94,10 @@ class TableDefinition<T> { ...@@ -94,6 +94,10 @@ class TableDefinition<T> {
tableName = clazz.getSimpleName(); tableName = clazz.getSimpleName();
} }
List<FieldDefinition> getFields() {
return fields;
}
void setTableName(String tableName) { void setTableName(String tableName) {
this.tableName = tableName; this.tableName = tableName;
} }
......
...@@ -9,7 +9,7 @@ package org.h2.jaqu; ...@@ -9,7 +9,7 @@ package org.h2.jaqu;
/** /**
* Classes implementing this interface can be used as a token in a statement. * Classes implementing this interface can be used as a token in a statement.
*/ */
interface Token { public interface Token {
/** /**
* Append the SQL to the given statement using the given query. * Append the SQL to the given statement using the given query.
* *
......
/*
* Copyright 2004-2009 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 org.h2.jaqu.Query;
import org.h2.jaqu.SQLStatement;
import org.h2.jaqu.Token;
/**
* An AND expression.
*/
public class And implements Token {
private final Token left, right;
private And(Token left, Token right) {
this.left = left;
this.right = right;
}
static And get(Token left, Token right) {
return new And(left, right);
}
public <T> void appendSQL(SQLStatement stat, Query<T> query) {
left.appendSQL(stat, query);
stat.appendSQL(" AND ");
right.appendSQL(stat, query);
}
}
/*
* Copyright 2004-2009 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 org.h2.jaqu.Query;
import org.h2.jaqu.SQLStatement;
import org.h2.jaqu.Token;
/**
* An array access operation.
*/
public class ArrayGet implements Token {
private final Token variable;
private final Token index;
private ArrayGet(Token variable, Token index) {
this.variable = variable;
this.index = index;
}
static ArrayGet get(Token variable, Token index) {
return new ArrayGet(variable, index);
}
public <T> void appendSQL(SQLStatement stat, Query<T> query) {
// untested
variable.appendSQL(stat, query);
stat.appendSQL("[");
index.appendSQL(stat, query);
stat.appendSQL("]");
}
}
/*
* Copyright 2004-2009 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 org.h2.jaqu.Query;
import org.h2.jaqu.SQLStatement;
import org.h2.jaqu.Token;
/**
* A conditional expression.
*/
public class CaseWhen implements Token {
private final Token condition, ifTrue, ifFalse;
private CaseWhen(Token condition, Token ifTrue, Token ifFalse) {
this.condition = condition;
this.ifTrue = ifTrue;
this.ifFalse = ifFalse;
}
static Token get(Token condition, Token ifTrue, Token ifFalse) {
if ("0".equals(ifTrue.toString()) && "1".equals(ifFalse.toString())) {
return Not.get(condition);
} else if ("1".equals(ifTrue.toString()) && "0".equals(ifFalse.toString())) {
return condition;
} else if ("0".equals(ifTrue.toString())) {
return And.get(Not.get(condition), ifFalse);
}
return new CaseWhen(condition, ifTrue, ifFalse);
}
public String toString() {
return "CASEWHEN(" + condition + ", " + ifTrue + ", " + ifFalse + ")";
}
public <T> void appendSQL(SQLStatement stat, Query<T> query) {
stat.appendSQL("CASEWHEN ");
condition.appendSQL(stat, query);
stat.appendSQL(" THEN ");
ifTrue.appendSQL(stat, query);
stat.appendSQL(" ELSE ");
ifFalse.appendSQL(stat, query);
stat.appendSQL(" END");
}
}
...@@ -4,16 +4,19 @@ ...@@ -4,16 +4,19 @@
* (http://h2database.com/html/license.html). * (http://h2database.com/html/license.html).
* Initial Developer: H2 Group * Initial Developer: H2 Group
*/ */
package org.h2.jaqu.util; package org.h2.jaqu.bytecode;
import java.io.ByteArrayOutputStream; import java.io.ByteArrayOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack; import java.util.Stack;
import org.h2.jaqu.Token;
/** /**
* This class converts a method to a SQL expression by interpreting * This class converts a method to a SQL Token by interpreting
* (decompiling) the bytecode of the class. * (decompiling) the bytecode of the class.
*/ */
public class ClassReader { public class ClassReader {
...@@ -22,19 +25,18 @@ public class ClassReader { ...@@ -22,19 +25,18 @@ public class ClassReader {
private byte[] data; private byte[] data;
private int pos; private int pos;
private int[] cpType; private Constant[] constantPool;
private String[] cpString;
private int[] cpInt;
private int startByteCode; private int startByteCode;
private String methodName; private String methodName;
private String convertMethodName; private String convertMethodName;
private String result; private Token result;
private Stack<String> stack = new Stack<String>(); private Stack<Token> stack = new Stack<Token>();
private ArrayList<String> variables = new ArrayList<String>(); private ArrayList<Token> variables = new ArrayList<Token>();
private boolean end; private boolean end;
private boolean condition; private boolean condition;
private int nextPc; private int nextPc;
private Map<String, Object> fieldMap = new HashMap<String, Object>();
private void debug(String s) { private void debug(String s) {
if (DEBUG) { if (DEBUG) {
...@@ -42,7 +44,8 @@ public class ClassReader { ...@@ -42,7 +44,8 @@ public class ClassReader {
} }
} }
public String decompile(Object instance, String methodName) { public Token decompile(Object instance, Map<String, Object> fieldMap, String methodName) {
this.fieldMap = fieldMap;
this.convertMethodName = methodName; this.convertMethodName = methodName;
Class< ? > clazz = instance.getClass(); Class< ? > clazz = instance.getClass();
String className = clazz.getName(); String className = clazz.getName();
...@@ -67,89 +70,79 @@ public class ClassReader { ...@@ -67,89 +70,79 @@ public class ClassReader {
int majorVersion = readShort(); int majorVersion = readShort();
debug("version: " + majorVersion + "." + minorVersion); debug("version: " + majorVersion + "." + minorVersion);
int constantPoolCount = readShort(); int constantPoolCount = readShort();
cpString = new String[constantPoolCount]; constantPool = new Constant[constantPoolCount];
cpInt = new int[constantPoolCount];
cpType = new int[constantPoolCount];
for (int i = 1; i < constantPoolCount; i++) { for (int i = 1; i < constantPoolCount; i++) {
int tag = readByte(); int type = readByte();
cpType[i] = tag; switch(type) {
switch(tag) {
case 1: case 1:
cpString[i] = readString(); constantPool[i] = ConstantString.get(readString());
break; break;
case 3: { case 3: {
int x = readInt(); int x = readInt();
cpString[i] = String.valueOf(x); constantPool[i] = ConstantNumber.get(x);
break; break;
} }
case 4: { case 4: {
int x = readInt(); int x = readInt();
cpString[i] = Float.toString(Float.intBitsToFloat(x)); constantPool[i] = ConstantNumber.get("" + Float.intBitsToFloat(x), x, Constant.Type.FLOAT);
cpInt[i] = x;
break; break;
} }
case 5: { case 5: {
long x = readLong(); long x = readLong();
cpString[i] = String.valueOf(x); constantPool[i] = ConstantNumber.get(x);
i++; i++;
break; break;
} }
case 6: { case 6: {
long x = readLong(); long x = readLong();
cpString[i] = String.valueOf(Double.longBitsToDouble(x)); constantPool[i] = ConstantNumber.get("" + Double.longBitsToDouble(x), x, Constant.Type.DOUBLE);
i++; i++;
break; break;
} }
case 7: { case 7: {
int x = readShort(); int x = readShort();
cpString[i] = "class"; constantPool[i] = ConstantNumber.get(null, x, ConstantNumber.Type.CLASS_REF);
cpInt[i] = x;
break; break;
} }
case 8: { case 8: {
int x = readShort(); int x = readShort();
cpString[i] = "string"; constantPool[i] = ConstantNumber.get(null, x, ConstantNumber.Type.STRING_REF);
cpInt[i] = x;
break; break;
} }
case 9: { case 9: {
int x = readInt(); int x = readInt();
cpString[i] = "field"; constantPool[i] = ConstantNumber.get(null, x, ConstantNumber.Type.FIELD_REF);
cpInt[i] = x;
break; break;
} }
case 10: { case 10: {
int x = readInt(); int x = readInt();
cpString[i] = "method"; constantPool[i] = ConstantNumber.get(null, x, ConstantNumber.Type.METHOD_REF);
cpInt[i] = x;
break; break;
} }
case 11: { case 11: {
int x = readInt(); int x = readInt();
cpString[i] = "interface method"; constantPool[i] = ConstantNumber.get(null, x, ConstantNumber.Type.INTERFACE_METHOD_REF);
cpInt[i] = x;
break; break;
} }
case 12: { case 12: {
int x = readInt(); int x = readInt();
cpString[i] = "name and type"; constantPool[i] = ConstantNumber.get(null, x, ConstantNumber.Type.NAME_AND_TYPE);
cpInt[i] = x;
break; break;
} }
default: default:
throw new RuntimeException("Unsupported constant pool tag: " + tag); throw new RuntimeException("Unsupported constant pool tag: " + type);
} }
} }
int accessFlags = readShort(); int accessFlags = readShort();
debug("access flags: " + accessFlags); debug("access flags: " + accessFlags);
int classRef = readShort(); int classRef = readShort();
debug("class: " + cpString[cpInt[classRef]]); debug("class: " + constantPool[constantPool[classRef].intValue()]);
int superClassRef = readShort(); int superClassRef = readShort();
debug(" extends " + cpString[cpInt[superClassRef]]); debug(" extends " + constantPool[constantPool[superClassRef].intValue()]);
int interfaceCount = readShort(); int interfaceCount = readShort();
for (int i = 0; i < interfaceCount; i++) { for (int i = 0; i < interfaceCount; i++) {
int interfaceRef = readShort(); int interfaceRef = readShort();
debug(" implements " + cpString[cpInt[interfaceRef]]); debug(" implements " + constantPool[constantPool[interfaceRef].intValue()]);
} }
int fieldCount = readShort(); int fieldCount = readShort();
for (int i = 0; i < fieldCount; i++) { for (int i = 0; i < fieldCount; i++) {
...@@ -167,7 +160,7 @@ public class ClassReader { ...@@ -167,7 +160,7 @@ public class ClassReader {
int accessFlags = readShort(); int accessFlags = readShort();
int nameIndex = readShort(); int nameIndex = readShort();
int descIndex = readShort(); int descIndex = readShort();
debug(" " + cpString[descIndex] + " " + cpString[nameIndex] + " " + accessFlags); debug(" " + constantPool[descIndex] + " " + constantPool[nameIndex] + " " + accessFlags);
readAttributes(); readAttributes();
} }
...@@ -175,8 +168,8 @@ public class ClassReader { ...@@ -175,8 +168,8 @@ public class ClassReader {
int accessFlags = readShort(); int accessFlags = readShort();
int nameIndex = readShort(); int nameIndex = readShort();
int descIndex = readShort(); int descIndex = readShort();
String desc = cpString[descIndex]; String desc = constantPool[descIndex].toString();
methodName = cpString[nameIndex]; methodName = constantPool[nameIndex].toString();
debug(" " + desc + " " + methodName + " " + accessFlags); debug(" " + desc + " " + methodName + " " + accessFlags);
readAttributes(); readAttributes();
} }
...@@ -185,7 +178,7 @@ public class ClassReader { ...@@ -185,7 +178,7 @@ public class ClassReader {
int attributeCount = readShort(); int attributeCount = readShort();
for (int i = 0; i < attributeCount; i++) { for (int i = 0; i < attributeCount; i++) {
int attributeNameIndex = readShort(); int attributeNameIndex = readShort();
String attributeName = cpString[attributeNameIndex]; String attributeName = constantPool[attributeNameIndex].toString();
debug(" attribute " + attributeName); debug(" attribute " + attributeName);
int attributeLength = readInt(); int attributeLength = readInt();
int end = pos + attributeLength; int end = pos + attributeLength;
...@@ -230,38 +223,38 @@ public class ClassReader { ...@@ -230,38 +223,38 @@ public class ClassReader {
readAttributes(); readAttributes();
} }
private String getResult() { private Token getResult() {
while (true) { while (true) {
readByteCode(); readByteCode();
if (end) { if (end) {
return stack.pop(); return stack.pop();
} }
if (condition) { if (condition) {
String c = stack.pop(); Token c = stack.pop();
Stack<String> currentStack = new Stack<String>(); Stack<Token> currentStack = new Stack<Token>();
currentStack.addAll(stack); currentStack.addAll(stack);
ArrayList<String> currentVariables = new ArrayList<String>(); ArrayList<Token> currentVariables = new ArrayList<Token>();
currentVariables.addAll(variables); currentVariables.addAll(variables);
int branch = nextPc; int branch = nextPc;
String a = getResult(); Token a = getResult();
stack = currentStack; stack = currentStack;
variables = currentVariables; variables = currentVariables;
pos = branch + startByteCode; pos = branch + startByteCode;
String b = getResult(); Token b = getResult();
if (a.equals("0") && b.equals("1")) { if (a.equals("0") && b.equals("1")) {
return c; return c;
} else if (a.equals("1") && b.equals("0")) { } else if (a.equals("1") && b.equals("0")) {
return "NOT(" +c + ")"; return Not.get(c);
} else if (b.equals("0")) { } else if (b.equals("0")) {
return "NOT(" + c + ") AND (" + a + ")"; return And.get(Not.get(c), a);
} else if (a.equals("0")) { } else if (a.equals("0")) {
return "(" + c + ") AND (" + b + ")"; return And.get(c, b);
} else if (b.equals("1")) { } else if (b.equals("1")) {
return "(" + c + ") OR (" + a + ")"; return Or.get(c, a);
} else if (a.equals("1")) { } else if (a.equals("1")) {
return "NOT(" + c + ") AND (" + b + ")"; return And.get(Not.get(c), b);
} }
return "(" + c + ") ? (" + b + ") : (" + a + ")"; return CaseWhen.get(c, b, a);
} }
if (nextPc != 0) { if (nextPc != 0) {
pos = nextPc + startByteCode; pos = nextPc + startByteCode;
...@@ -282,90 +275,90 @@ public class ClassReader { ...@@ -282,90 +275,90 @@ public class ClassReader {
break; break;
case 1: case 1:
op = "aconst_null"; op = "aconst_null";
stack.push("null"); stack.push(Null.INSTANCE);
break; break;
case 2: case 2:
op = "iconst_m1"; op = "iconst_m1";
stack.push("-1"); stack.push(ConstantNumber.get("-1"));
break; break;
case 3: case 3:
op = "iconst_0"; op = "iconst_0";
stack.push("0"); stack.push(ConstantNumber.get("0"));
break; break;
case 4: case 4:
op = "iconst_1"; op = "iconst_1";
stack.push("1"); stack.push(ConstantNumber.get("1"));
break; break;
case 5: case 5:
op = "iconst_2"; op = "iconst_2";
stack.push("2"); stack.push(ConstantNumber.get("2"));
break; break;
case 6: case 6:
op = "iconst_3"; op = "iconst_3";
stack.push("3"); stack.push(ConstantNumber.get("3"));
break; break;
case 7: case 7:
op = "iconst_4"; op = "iconst_4";
stack.push("4"); stack.push(ConstantNumber.get("4"));
break; break;
case 8: case 8:
op = "iconst_5"; op = "iconst_5";
stack.push("5"); stack.push(ConstantNumber.get("5"));
break; break;
case 9: case 9:
op = "lconst_0"; op = "lconst_0";
stack.push("0"); stack.push(ConstantNumber.get("0"));
break; break;
case 10: case 10:
op = "lconst_1"; op = "lconst_1";
stack.push("1"); stack.push(ConstantNumber.get("1"));
break; break;
case 11: case 11:
op = "fconst_0"; op = "fconst_0";
stack.push("0.0"); stack.push(ConstantNumber.get("0.0"));
break; break;
case 12: case 12:
op = "fconst_1"; op = "fconst_1";
stack.push("1.0"); stack.push(ConstantNumber.get("1.0"));
break; break;
case 13: case 13:
op = "fconst_2"; op = "fconst_2";
stack.push("2.0"); stack.push(ConstantNumber.get("2.0"));
break; break;
case 14: case 14:
op = "dconst_0"; op = "dconst_0";
stack.push("0.0"); stack.push(ConstantNumber.get("0.0"));
break; break;
case 15: case 15:
op = "dconst_1"; op = "dconst_1";
stack.push("1.0"); stack.push(ConstantNumber.get("1.0"));
break; break;
case 16: { case 16: {
int x = (byte) readByte(); int x = (byte) readByte();
op = "bipush " + x; op = "bipush " + x;
stack.push("" + x); stack.push(ConstantNumber.get(x));
break; break;
} }
case 17: { case 17: {
int x = (short) readShort(); int x = (short) readShort();
op = "sipush " + x; op = "sipush " + x;
stack.push("" + x); stack.push(ConstantNumber.get(x));
break; break;
} }
case 18: { case 18: {
String s = getConstant(readByte()); Token s = getConstant(readByte());
op = "ldc " + s; op = "ldc " + s;
stack.push(s); stack.push(s);
break; break;
} }
case 19: { case 19: {
String s = getConstant(readShort()); Token s = getConstant(readShort());
op = "ldc_w " + s; op = "ldc_w " + s;
stack.push(s); stack.push(s);
break; break;
} }
case 20: { case 20: {
String s = getConstant(readShort()); Token s = getConstant(readShort());
op = "ldc2_w " + s; op = "ldc2_w " + s;
stack.push(s); stack.push(s);
break; break;
...@@ -481,59 +474,59 @@ public class ClassReader { ...@@ -481,59 +474,59 @@ public class ClassReader {
stack.push(getVariable(3)); stack.push(getVariable(3));
break; break;
case 46: { case 46: {
String index = stack.pop(); Token index = stack.pop();
String ref = stack.pop(); Token ref = stack.pop();
op = "iaload"; op = "iaload";
stack.push(ref + "[" + index + "]"); stack.push(ArrayGet.get(ref, index));
break; break;
} }
case 47: { case 47: {
String index = stack.pop(); Token index = stack.pop();
String ref = stack.pop(); Token ref = stack.pop();
op = "laload"; op = "laload";
stack.push(ref + "[" + index + "]"); stack.push(ArrayGet.get(ref, index));
break; break;
} }
case 48: { case 48: {
String index = stack.pop(); Token index = stack.pop();
String ref = stack.pop(); Token ref = stack.pop();
op = "faload"; op = "faload";
stack.push(ref + "[" + index + "]"); stack.push(ArrayGet.get(ref, index));
break; break;
} }
case 49: { case 49: {
String index = stack.pop(); Token index = stack.pop();
String ref = stack.pop(); Token ref = stack.pop();
op = "daload"; op = "daload";
stack.push(ref + "[" + index + "]"); stack.push(ArrayGet.get(ref, index));
break; break;
} }
case 50: { case 50: {
String index = stack.pop(); Token index = stack.pop();
String ref = stack.pop(); Token ref = stack.pop();
op = "aaload"; op = "aaload";
stack.push(ref + "[" + index + "]"); stack.push(ArrayGet.get(ref, index));
break; break;
} }
case 51: { case 51: {
String index = stack.pop(); Token index = stack.pop();
String ref = stack.pop(); Token ref = stack.pop();
op = "baload"; op = "baload";
stack.push(ref + "[" + index + "]"); stack.push(ArrayGet.get(ref, index));
break; break;
} }
case 52: { case 52: {
String index = stack.pop(); Token index = stack.pop();
String ref = stack.pop(); Token ref = stack.pop();
op = "caload"; op = "caload";
stack.push(ref + "[" + index + "]"); stack.push(ArrayGet.get(ref, index));
break; break;
} }
case 53: { case 53: {
String index = stack.pop(); Token index = stack.pop();
String ref = stack.pop(); Token ref = stack.pop();
op = "saload"; op = "saload";
stack.push(ref + "[" + index + "]"); stack.push(ArrayGet.get(ref, index));
break; break;
} }
case 54: { case 54: {
...@@ -694,15 +687,15 @@ public class ClassReader { ...@@ -694,15 +687,15 @@ public class ClassReader {
break; break;
case 89: { case 89: {
op = "dup"; op = "dup";
String x = stack.pop(); Token x = stack.pop();
stack.push(x); stack.push(x);
stack.push(x); stack.push(x);
break; break;
} }
case 90: { case 90: {
op = "dup_x1"; op = "dup_x1";
String a = stack.pop(); Token a = stack.pop();
String b = stack.pop(); Token b = stack.pop();
stack.push(a); stack.push(a);
stack.push(b); stack.push(b);
stack.push(a); stack.push(a);
...@@ -711,9 +704,9 @@ public class ClassReader { ...@@ -711,9 +704,9 @@ public class ClassReader {
case 91: { case 91: {
// TODO currently we don't know the stack types // TODO currently we don't know the stack types
op = "dup_x2"; op = "dup_x2";
String a = stack.pop(); Token a = stack.pop();
String b = stack.pop(); Token b = stack.pop();
String c = stack.pop(); Token c = stack.pop();
stack.push(a); stack.push(a);
stack.push(c); stack.push(c);
stack.push(b); stack.push(b);
...@@ -723,8 +716,8 @@ public class ClassReader { ...@@ -723,8 +716,8 @@ public class ClassReader {
case 92: { case 92: {
// TODO currently we don't know the stack types // TODO currently we don't know the stack types
op = "dup2"; op = "dup2";
String a = stack.pop(); Token a = stack.pop();
String b = stack.pop(); Token b = stack.pop();
stack.push(b); stack.push(b);
stack.push(a); stack.push(a);
stack.push(b); stack.push(b);
...@@ -734,9 +727,9 @@ public class ClassReader { ...@@ -734,9 +727,9 @@ public class ClassReader {
case 93: { case 93: {
// TODO currently we don't know the stack types // TODO currently we don't know the stack types
op = "dup2_x1"; op = "dup2_x1";
String a = stack.pop(); Token a = stack.pop();
String b = stack.pop(); Token b = stack.pop();
String c = stack.pop(); Token c = stack.pop();
stack.push(b); stack.push(b);
stack.push(a); stack.push(a);
stack.push(c); stack.push(c);
...@@ -747,10 +740,10 @@ public class ClassReader { ...@@ -747,10 +740,10 @@ public class ClassReader {
case 94: { case 94: {
// TODO currently we don't know the stack types // TODO currently we don't know the stack types
op = "dup2_x2"; op = "dup2_x2";
String a = stack.pop(); Token a = stack.pop();
String b = stack.pop(); Token b = stack.pop();
String c = stack.pop(); Token c = stack.pop();
String d = stack.pop(); Token d = stack.pop();
stack.push(b); stack.push(b);
stack.push(a); stack.push(a);
stack.push(d); stack.push(d);
...@@ -761,410 +754,410 @@ public class ClassReader { ...@@ -761,410 +754,410 @@ public class ClassReader {
} }
case 95: { case 95: {
op = "swap"; op = "swap";
String a = stack.pop(); Token a = stack.pop();
String b = stack.pop(); Token b = stack.pop();
stack.push(a); stack.push(a);
stack.push(b); stack.push(b);
break; break;
} }
case 96: { case 96: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "iadd"; op = "iadd";
stack.push("(" + a + " + " + b + ")"); stack.push(Operation.get(a, Operation.Type.ADD, b));
break; break;
} }
case 97: { case 97: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "ladd"; op = "ladd";
stack.push("(" + a + " + " + b + ")"); stack.push(Operation.get(a, Operation.Type.ADD, b));
break; break;
} }
case 98: { case 98: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "fadd"; op = "fadd";
stack.push("(" + a + " + " + b + ")"); stack.push(Operation.get(a, Operation.Type.ADD, b));
break; break;
} }
case 99: { case 99: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "dadd"; op = "dadd";
stack.push("(" + a + " + " + b + ")"); stack.push(Operation.get(a, Operation.Type.ADD, b));
break; break;
} }
case 100: { case 100: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "isub"; op = "isub";
stack.push("(" + a + " - " + b + ")"); stack.push(Operation.get(a, Operation.Type.SUBTRACT, b));
break; break;
} }
case 101: { case 101: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "lsub"; op = "lsub";
stack.push("(" + a + " - " + b + ")"); stack.push(Operation.get(a, Operation.Type.SUBTRACT, b));
break; break;
} }
case 102: { case 102: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "fsub"; op = "fsub";
stack.push("(" + a + " - " + b + ")"); stack.push(Operation.get(a, Operation.Type.SUBTRACT, b));
break; break;
} }
case 103: { case 103: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "dsub"; op = "dsub";
stack.push("(" + a + " - " + b + ")"); stack.push(Operation.get(a, Operation.Type.SUBTRACT, b));
break; break;
} }
case 104: { case 104: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "imul"; op = "imul";
stack.push("(" + a + " * " + b + ")"); stack.push(Operation.get(a, Operation.Type.MULTIPLY, b));
break; break;
} }
case 105: { case 105: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "lmul"; op = "lmul";
stack.push("(" + a + " * " + b + ")"); stack.push(Operation.get(a, Operation.Type.MULTIPLY, b));
break; break;
} }
case 106: { case 106: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "fmul"; op = "fmul";
stack.push("(" + a + " * " + b + ")"); stack.push(Operation.get(a, Operation.Type.MULTIPLY, b));
break; break;
} }
case 107: { case 107: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "dmul"; op = "dmul";
stack.push("(" + a + " * " + b + ")"); stack.push(Operation.get(a, Operation.Type.MULTIPLY, b));
break; break;
} }
case 108: { case 108: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "idiv"; op = "idiv";
stack.push("(" + a + " / " + b + ")"); stack.push(Operation.get(a, Operation.Type.DIVIDE, b));
break; break;
} }
case 109: { case 109: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "ldiv"; op = "ldiv";
stack.push("(" + a + " / " + b + ")"); stack.push(Operation.get(a, Operation.Type.DIVIDE, b));
break; break;
} }
case 110: { case 110: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "fdiv"; op = "fdiv";
stack.push("(" + a + " / " + b + ")"); stack.push(Operation.get(a, Operation.Type.DIVIDE, b));
break; break;
} }
case 111: { case 111: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "ddiv"; op = "ddiv";
stack.push("(" + a + " / " + b + ")"); stack.push(Operation.get(a, Operation.Type.DIVIDE, b));
break; break;
} }
case 112: { case 112: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "irem"; op = "irem";
stack.push("(" + a + " % " + b + ")"); stack.push(Operation.get(a, Operation.Type.MOD, b));
break; break;
} }
case 113: { case 113: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "lrem"; op = "lrem";
stack.push("(" + a + " % " + b + ")"); stack.push(Operation.get(a, Operation.Type.MOD, b));
break; break;
} }
case 114: { case 114: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "frem"; op = "frem";
stack.push("(" + a + " % " + b + ")"); stack.push(Operation.get(a, Operation.Type.MOD, b));
break; break;
} }
case 115: { case 115: {
String b = stack.pop(); Token b = stack.pop();
String a = stack.pop(); Token a = stack.pop();
op = "drem"; op = "drem";
stack.push("(" + a + " % " + b + ")"); stack.push(Operation.get(a, Operation.Type.MOD, b));
break; break;
} }
case 116: // case 116:
op = "ineg"; // op = "ineg";
break; // break;
case 117: // case 117:
op = "lneg"; // op = "lneg";
break; // break;
case 118: // case 118:
op = "fneg"; // op = "fneg";
break; // break;
case 119: // case 119:
op = "dneg"; // op = "dneg";
break; // break;
case 120: // case 120:
op = "ishl"; // op = "ishl";
break; // break;
case 121: // case 121:
op = "lshl"; // op = "lshl";
break; // break;
case 122: // case 122:
op = "ishr"; // op = "ishr";
break; // break;
case 123: // case 123:
op = "lshr"; // op = "lshr";
break; // break;
case 124: // case 124:
op = "iushr"; // op = "iushr";
break; // break;
case 125: // case 125:
op = "lushr"; // op = "lushr";
break; // break;
case 126: // case 126:
op = "iand"; // op = "iand";
break; // break;
case 127: // case 127:
op = "land"; // op = "land";
break; // break;
case 128: // case 128:
op = "ior"; // op = "ior";
break; // break;
case 129: // case 129:
op = "lor"; // op = "lor";
break; // break;
case 130: // case 130:
op = "ixor"; // op = "ixor";
break; // break;
case 131: // case 131:
op = "lxor"; // op = "lxor";
break; // break;
case 132: { // case 132: {
int var = readByte(); // int var = readByte();
int off = (byte) readByte(); // int off = (byte) readByte();
op = "iinc " + var + " " + off; // op = "iinc " + var + " " + off;
break; // break;
} // }
case 133: // case 133:
op = "i2l"; // op = "i2l";
break; // break;
case 134: // case 134:
op = "i2f"; // op = "i2f";
break; // break;
case 135: // case 135:
op = "i2d"; // op = "i2d";
break; // break;
case 136: // case 136:
op = "l2i"; // op = "l2i";
break; // break;
case 137: // case 137:
op = "l2f"; // op = "l2f";
break; // break;
case 138: // case 138:
op = "l2d"; // op = "l2d";
break; // break;
case 139: // case 139:
op = "f2i"; // op = "f2i";
break; // break;
case 140: // case 140:
op = "f2l"; // op = "f2l";
break; // break;
case 141: // case 141:
op = "f2d"; // op = "f2d";
break; // break;
case 142: // case 142:
op = "d2i"; // op = "d2i";
break; // break;
case 143: // case 143:
op = "d2l"; // op = "d2l";
break; // break;
case 144: // case 144:
op = "d2f"; // op = "d2f";
break; // break;
case 145: // case 145:
op = "i2b"; // op = "i2b";
break; // break;
case 146: // case 146:
op = "i2c"; // op = "i2c";
break; // break;
case 147: // case 147:
op = "i2s"; // op = "i2s";
break; // break;
case 148: { case 148: {
String b = stack.pop(), a = stack.pop(); Token b = stack.pop(), a = stack.pop();
stack.push("SIGN(" + a + " - " + b + ")"); stack.push(new Function("SIGN", Operation.get(a, Operation.Type.SUBTRACT, b)));
op = "lcmp"; op = "lcmp";
break; break;
} }
case 149: // case 149:
op = "fcmpl"; // op = "fcmpl";
break; // break;
case 150: // case 150:
op = "fcmpg"; // op = "fcmpg";
break; // break;
case 151: // case 151:
op = "dcmpl"; // op = "dcmpl";
break; // break;
case 152: // case 152:
op = "dcmpg"; // op = "dcmpg";
break; // break;
case 153: case 153:
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
stack.push("(" + stack.pop() + " = 0)"); stack.push(Operation.get(stack.pop(), Operation.Type.EQUALS, ConstantNumber.get(0)));
op = "ifeq " + nextPc; op = "ifeq " + nextPc;
break; break;
case 154: case 154:
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
stack.push("(" + stack.pop() + " <> 0)"); stack.push(Operation.get(stack.pop(), Operation.Type.NOT_EQUALS, ConstantNumber.get(0)));
op = "ifne " + nextPc; op = "ifne " + nextPc;
break; break;
case 155: case 155:
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
stack.push("(" + stack.pop() + " < 0)"); stack.push(Operation.get(stack.pop(), Operation.Type.SMALLER, ConstantNumber.get(0)));
op = "iflt " + nextPc; op = "iflt " + nextPc;
break; break;
case 156: case 156:
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
stack.push("(" + stack.pop() + " >= 0)"); stack.push(Operation.get(stack.pop(), Operation.Type.BIGGER_EQUALS, ConstantNumber.get(0)));
op = "ifge " + nextPc; op = "ifge " + nextPc;
break; break;
case 157: case 157:
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
stack.push("(" + stack.pop() + " > 0)"); stack.push(Operation.get(stack.pop(), Operation.Type.BIGGER, ConstantNumber.get(0)));
op = "ifgt " + nextPc; op = "ifgt " + nextPc;
break; break;
case 158: case 158:
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
stack.push("(" + stack.pop() + "<= 0)"); stack.push(Operation.get(stack.pop(), Operation.Type.SMALLER_EQUALS, ConstantNumber.get(0)));
op = "ifle " + nextPc; op = "ifle " + nextPc;
break; break;
case 159: { case 159: {
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
String b = stack.pop(), a = stack.pop(); Token b = stack.pop(), a = stack.pop();
stack.push("(" + a + " = " + b + ")"); stack.push(Operation.get(a, Operation.Type.EQUALS, b));
op = "if_icmpeq " + nextPc; op = "if_icmpeq " + nextPc;
break; break;
} }
case 160: { case 160: {
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
String b = stack.pop(), a = stack.pop(); Token b = stack.pop(), a = stack.pop();
stack.push("(" + a + " <> " + b + ")"); stack.push(Operation.get(a, Operation.Type.NOT_EQUALS, b));
op = "if_icmpne " + nextPc; op = "if_icmpne " + nextPc;
break; break;
} }
case 161: { case 161: {
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
String b = stack.pop(), a = stack.pop(); Token b = stack.pop(), a = stack.pop();
stack.push("(" + a + " < " + b + ")"); stack.push(Operation.get(a, Operation.Type.SMALLER, b));
op = "if_icmplt " + nextPc; op = "if_icmplt " + nextPc;
break; break;
} }
case 162: { case 162: {
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
String b = stack.pop(), a = stack.pop(); Token b = stack.pop(), a = stack.pop();
stack.push("(" + a + " >= " + b + ")"); stack.push(Operation.get(a, Operation.Type.BIGGER_EQUALS, b));
op = "if_icmpge " + nextPc; op = "if_icmpge " + nextPc;
break; break;
} }
case 163: { case 163: {
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
String b = stack.pop(), a = stack.pop(); Token b = stack.pop(), a = stack.pop();
stack.push("(" + a + " > " + b + ")"); stack.push(Operation.get(a, Operation.Type.BIGGER, b));
op = "if_icmpgt " + nextPc; op = "if_icmpgt " + nextPc;
break; break;
} }
case 164: { case 164: {
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
String b = stack.pop(), a = stack.pop(); Token b = stack.pop(), a = stack.pop();
stack.push("(" + a + " <= " + b + ")"); stack.push(Operation.get(a, Operation.Type.SMALLER_EQUALS, b));
op = "if_icmple " + nextPc; op = "if_icmple " + nextPc;
break; break;
} }
case 165: { case 165: {
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
String b = stack.pop(), a = stack.pop(); Token b = stack.pop(), a = stack.pop();
stack.push("(" + a + " = " + b + ")"); stack.push(Operation.get(a, Operation.Type.EQUALS, b));
op = "if_acmpeq " + nextPc; op = "if_acmpeq " + nextPc;
break; break;
} }
case 166: { case 166: {
condition = true; condition = true;
nextPc = getAbsolutePos(pos, readShort()); nextPc = getAbsolutePos(pos, readShort());
String b = stack.pop(), a = stack.pop(); Token b = stack.pop(), a = stack.pop();
stack.push("(" + a + " <> " + b + ")"); stack.push(Operation.get(a, Operation.Type.NOT_EQUALS, b));
op = "if_acmpne " + nextPc; op = "if_acmpne " + nextPc;
break; break;
} }
case 167: // case 167:
nextPc = getAbsolutePos(pos, readShort()); // nextPc = getAbsolutePos(pos, readShort());
op = "goto " + nextPc; // op = "goto " + nextPc;
break; // break;
case 168: // case 168:
// TODO not supported yet // // TODO not supported yet
op = "jsr " + getAbsolutePos(pos, readShort()); // op = "jsr " + getAbsolutePos(pos, readShort());
break; // break;
case 169: // case 169:
// TODO not supported yet // // TODO not supported yet
op = "ret " + readByte(); // op = "ret " + readByte();
break; // break;
case 170: { // case 170: {
int start = pos; // int start = pos;
pos += 4 - ((pos - startByteCode) & 3); // pos += 4 - ((pos - startByteCode) & 3);
int def = readInt(); // int def = readInt();
int low = readInt(), high = readInt(); // int low = readInt(), high = readInt();
int n = high - low + 1; // int n = high - low + 1;
op = "tableswitch default:" + getAbsolutePos(start, def); // op = "tableswitch default:" + getAbsolutePos(start, def);
StringBuilder buff = new StringBuilder(); // StringBuilder buff = new StringBuilder();
for (int i = 0; i < n; i++) { // for (int i = 0; i < n; i++) {
buff.append(' ').append(low++).append(":").append(getAbsolutePos(start, readInt())); // buff.append(' ').append(low++).append(":").append(getAbsolutePos(start, readInt()));
} // }
op += buff.toString(); // op += buff.toString();
// pos += n * 4; // // pos += n * 4;
break; // break;
} // }
case 171: { // case 171: {
int start = pos; // int start = pos;
pos += 4 - ((pos - startByteCode) & 3); // pos += 4 - ((pos - startByteCode) & 3);
int def = readInt(); // int def = readInt();
int n = readInt(); // int n = readInt();
op = "lookupswitch default:" + getAbsolutePos(start, def); // op = "lookupswitch default:" + getAbsolutePos(start, def);
StringBuilder buff = new StringBuilder(); // StringBuilder buff = new StringBuilder();
for (int i = 0; i < n; i++) { // for (int i = 0; i < n; i++) {
buff.append(' ').append(readInt()).append(":").append(getAbsolutePos(start, readInt())); // buff.append(' ').append(readInt()).append(":").append(getAbsolutePos(start, readInt()));
} // }
op += buff.toString(); // op += buff.toString();
// pos += n * 8; // // pos += n * 8;
break; // break;
} // }
case 172: case 172:
op = "ireturn"; op = "ireturn";
end = true; end = true;
...@@ -1191,33 +1184,33 @@ public class ClassReader { ...@@ -1191,33 +1184,33 @@ public class ClassReader {
stack.push(null); stack.push(null);
end = true; end = true;
break; break;
case 178: // case 178:
op = "getstatic " + getField(readShort()); // op = "getstatic " + getField(readShort());
break; // break;
case 179: // case 179:
op = "putstatic " + getField(readShort()); // op = "putstatic " + getField(readShort());
break; // break;
case 180: { case 180: {
String field = getField(readShort()); String field = getField(readShort());
String p = stack.pop(); Token p = stack.pop();
p = p + "." + field.substring(Math.max(field.lastIndexOf('$'), field.lastIndexOf('.')) + 1, field.indexOf(' ')); String s = p + "." + field.substring(field.lastIndexOf('.') + 1, field.indexOf(' '));
if (p.startsWith("this.")) { if (s.startsWith("this.")) {
p = p.substring(5); s = s.substring(5);
} }
stack.push(p); stack.push(Variable.get(s, fieldMap.get(s)));
op = "getfield " + field; op = "getfield " + field;
break; break;
} }
case 181: // case 181:
op = "putfield " + getField(readShort()); // op = "putfield " + getField(readShort());
break; // break;
case 182: { case 182: {
String method = getMethod(readShort()); String method = getMethod(readShort());
op = "invokevirtual " + method; op = "invokevirtual " + method;
if (method.equals("java/lang/String.equals (Ljava/lang/Object;)Z")) { if (method.equals("java/lang/String.equals (Ljava/lang/Object;)Z")) {
String a = stack.pop(); Token a = stack.pop();
String b = stack.pop(); Token b = stack.pop();
stack.push("(" + a + " = " + b + ")"); stack.push(Operation.get(a, Operation.Type.EQUALS, b));
} else if (method.equals("java/lang/Integer.intValue ()I")) { } else if (method.equals("java/lang/Integer.intValue ()I")) {
// ignore // ignore
} else if (method.equals("java/lang/Long.longValue ()J")) { } else if (method.equals("java/lang/Long.longValue ()J")) {
...@@ -1225,112 +1218,116 @@ public class ClassReader { ...@@ -1225,112 +1218,116 @@ public class ClassReader {
} }
break; break;
} }
case 183: case 183: {
op = "invokespecial " + getMethod(readShort()); String methodName = getMethod(readShort());
op = "invokespecial " + methodName;
break; break;
}
case 184: case 184:
op = "invokestatic " + getMethod(readShort()); op = "invokestatic " + getMethod(readShort());
break; break;
case 185: { // case 185: {
int methodRef = readShort(); // int methodRef = readShort();
readByte(); // readByte();
readByte(); // readByte();
op = "invokeinterface " + getMethod(methodRef); // op = "invokeinterface " + getMethod(methodRef);
break; // break;
} // }
case 187: case 187: {
op = "new " + cpString[cpInt[readShort()]]; String className = constantPool[constantPool[readShort()].intValue()].toString();
break; op = "new " + className;
case 188: break;
op = "newarray " + readByte(); }
break; // case 188:
case 189: // op = "newarray " + readByte();
op = "anewarray " + cpString[readShort()]; // break;
break; // case 189:
case 190: // op = "anewarray " + cpString[readShort()];
op = "arraylength"; // break;
break; // case 190:
case 191: // op = "arraylength";
op = "athrow"; // break;
break; // case 191:
case 192: // op = "athrow";
op = "checkcast " + cpString[readShort()]; // break;
break; // case 192:
case 193: // op = "checkcast " + cpString[readShort()];
op = "instanceof " + cpString[readShort()]; // break;
break; // case 193:
case 194: // op = "instanceof " + cpString[readShort()];
op = "monitorenter"; // break;
break; // case 194:
case 195: // op = "monitorenter";
op = "monitorexit"; // break;
break; // case 195:
case 196: { // op = "monitorexit";
opCode = readByte(); // break;
switch (opCode) { // case 196: {
case 21: // opCode = readByte();
op = "wide iload " + readShort(); // switch (opCode) {
break; // case 21:
case 22: // op = "wide iload " + readShort();
op = "wide lload " + readShort(); // break;
break; // case 22:
case 23: // op = "wide lload " + readShort();
op = "wide fload " + readShort(); // break;
break; // case 23:
case 24: // op = "wide fload " + readShort();
op = "wide dload " + readShort(); // break;
break; // case 24:
case 25: // op = "wide dload " + readShort();
op = "wide aload " + readShort(); // break;
break; // case 25:
case 54: // op = "wide aload " + readShort();
op = "wide istore " + readShort(); // break;
break; // case 54:
case 55: // op = "wide istore " + readShort();
op = "wide lstore " + readShort(); // break;
break; // case 55:
case 56: // op = "wide lstore " + readShort();
op = "wide fstore " + readShort(); // break;
break; // case 56:
case 57: // op = "wide fstore " + readShort();
op = "wide dstore " + readShort(); // break;
break; // case 57:
case 58: // op = "wide dstore " + readShort();
op = "wide astore " + readShort(); // break;
break; // case 58:
case 132: { // op = "wide astore " + readShort();
int var = readShort(); // break;
int off = (short) readShort(); // case 132: {
op = "wide iinc " + var + " " + off; // int var = readShort();
break; // int off = (short) readShort();
} // op = "wide iinc " + var + " " + off;
case 169: // break;
op = "wide ret " + readShort(); // }
break; // case 169:
default: // op = "wide ret " + readShort();
throw new RuntimeException("Unsupported wide opCode " + opCode); // break;
} // default:
break; // throw new RuntimeException("Unsupported wide opCode " + opCode);
} // }
case 197: // break;
op = "multianewarray " + cpString[readShort()] + " " + readByte(); // }
break; // case 197:
case 198: { // op = "multianewarray " + cpString[readShort()] + " " + readByte();
condition = true; // break;
nextPc = getAbsolutePos(pos, readShort()); // case 198: {
String a = stack.pop(); // condition = true;
stack.push("(" + a + " IS NULL)"); // nextPc = getAbsolutePos(pos, readShort());
op = "ifnull " + nextPc; // Token a = stack.pop();
break; // stack.push("(" + a + " IS NULL)");
} // op = "ifnull " + nextPc;
case 199: { // break;
condition = true; // }
nextPc = getAbsolutePos(pos, readShort()); // case 199: {
String a = stack.pop(); // condition = true;
stack.push("(" + a + " IS NOT NULL)"); // nextPc = getAbsolutePos(pos, readShort());
op = "ifnonnull " + nextPc; // Token a = stack.pop();
break; // stack.push("(" + a + " IS NOT NULL)");
} // op = "ifnonnull " + nextPc;
// break;
// }
case 200: case 200:
op = "goto_w " + getAbsolutePos(pos, readInt()); op = "goto_w " + getAbsolutePos(pos, readInt());
break; break;
...@@ -1343,57 +1340,49 @@ public class ClassReader { ...@@ -1343,57 +1340,49 @@ public class ClassReader {
debug(" " + startPos + ": " + op); debug(" " + startPos + ": " + op);
} }
private void setVariable(int x, String value) { private void setVariable(int x, Token value) {
while (x >= variables.size()) { while (x >= variables.size()) {
variables.add("p" + variables.size()); variables.add(Variable.get("p" + variables.size(), null));
} }
variables.set(x, value); variables.set(x, value);
} }
private String getVariable(int x) { private Token getVariable(int x) {
if (x == 0) { if (x == 0) {
return "this"; return Variable.THIS;
} }
while (x >= variables.size()) { while (x >= variables.size()) {
variables.add("p" + variables.size()); variables.add(Variable.get("p" + variables.size(), null));
} }
return variables.get(x); return variables.get(x);
} }
private String getField(int fieldRef) { private String getField(int fieldRef) {
int field = cpInt[fieldRef]; int field = constantPool[fieldRef].intValue();
int classIndex = field >>> 16; int classIndex = field >>> 16;
int nameAndType = cpInt[field & 0xffff]; int nameAndType = constantPool[field & 0xffff].intValue();
String className = cpString[cpInt[classIndex]] + "." + cpString[nameAndType >>> 16] + " " + cpString[nameAndType & 0xffff]; String className = constantPool[constantPool[classIndex].intValue()] + "." + constantPool[nameAndType >>> 16] + " " + constantPool[nameAndType & 0xffff];
return className; return className;
} }
private String getMethod(int methodRef) { private String getMethod(int methodRef) {
int method = cpInt[methodRef]; int method = constantPool[methodRef].intValue();
int classIndex = method >>> 16; int classIndex = method >>> 16;
int nameAndType = cpInt[method & 0xffff]; int nameAndType = constantPool[method & 0xffff].intValue();
String className = cpString[cpInt[classIndex]] + "." + cpString[nameAndType >>> 16] + " " + cpString[nameAndType & 0xffff]; String className = constantPool[constantPool[classIndex].intValue()] + "." + constantPool[nameAndType >>> 16] + " " + constantPool[nameAndType & 0xffff];
return className; return className;
} }
private String getConstant(int constantRef) { private Constant getConstant(int constantRef) {
switch (cpType[constantRef]) { Constant c = constantPool[constantRef];
case 3: switch (c.getType()) {
// int case INT:
return cpString[constantRef]; case FLOAT:
case 4: case DOUBLE:
// float case LONG:
return cpString[constantRef]; return c;
case 5: case STRING_REF:
// long return constantPool[c.intValue()];
return cpString[constantRef];
case 6:
// double
return cpString[constantRef];
case 8:
// string
// TODO escape
return "\"" + cpString[cpInt[constantRef]] + "\"";
default: default:
throw new RuntimeException("Not a constant: " + constantRef); throw new RuntimeException("Not a constant: " + constantRef);
} }
......
/*
* Copyright 2004-2009 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 org.h2.jaqu.Token;
/**
* An expression in the constant pool.
*/
public interface Constant extends Token {
/**
* The constant pool type.
*/
enum Type {
STRING,
INT,
FLOAT,
DOUBLE,
LONG,
CLASS_REF,
STRING_REF,
FIELD_REF,
METHOD_REF,
INTERFACE_METHOD_REF,
NAME_AND_TYPE
}
Constant.Type getType();
int intValue();
}
/*
* Copyright 2004-2009 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 org.h2.jaqu.Query;
import org.h2.jaqu.SQLStatement;
/**
* A literal number.
*/
public class ConstantNumber implements Constant {
private final String value;
private final Type type;
private final long longValue;
private ConstantNumber(String value, long longValue, Type type) {
this.value = value;
this.longValue = longValue;
this.type = type;
}
static ConstantNumber get(String v) {
return new ConstantNumber(v, 0, Type.STRING);
}
static ConstantNumber get(int v) {
return new ConstantNumber("" + v, v, Type.INT);
}
static ConstantNumber get(long v) {
return new ConstantNumber("" + v, v, Type.LONG);
}
static ConstantNumber get(String s, long x, Type type) {
return new ConstantNumber(s, x, type);
}
public int intValue() {
return (int) longValue;
}
public String toString() {
return value;
}
public <T> void appendSQL(SQLStatement stat, Query<T> query) {
stat.appendSQL(toString());
}
public Constant.Type getType() {
return type;
}
}
/*
* Copyright 2004-2009 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 org.h2.jaqu.Query;
import org.h2.jaqu.SQLStatement;
import org.h2.util.StringUtils;
/**
* A string constant.
*/
public class ConstantString implements Constant {
private final String value;
private ConstantString(String value) {
this.value = value;
}
static ConstantString get(String v) {
return new ConstantString(v);
}
public String toString() {
return value;
}
public int intValue() {
return 0;
}
public <T> void appendSQL(SQLStatement stat, Query<T> query) {
stat.appendSQL(StringUtils.quoteStringSQL(value));
}
public Constant.Type getType() {
return Constant.Type.STRING;
}
}
/*
* Copyright 2004-2009 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 org.h2.jaqu.Query;
import org.h2.jaqu.SQLStatement;
import org.h2.jaqu.Token;
/**
* A method call.
*/
class Function implements Token {
private final String name;
private final Token expr;
Function(String name, Token expr) {
this.name = name;
this.expr = expr;
}
public String toString() {
return name + "(" + expr + ")";
}
public <T> void appendSQL(SQLStatement stat, Query<T> query) {
// untested
stat.appendSQL(name + "(");
expr.appendSQL(stat, query);
stat.appendSQL(")");
}
}
/*
* Copyright 2004-2009 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 org.h2.jaqu.Query;
import org.h2.jaqu.SQLStatement;
import org.h2.jaqu.Token;
/**
* A NOT condition.
*/
public class Not implements Token {
private Token expr;
private Not(Token expr) {
this.expr = expr;
}
static Token get(Token expr) {
if (expr instanceof Not) {
return ((Not) expr).expr;
} else if (expr instanceof Operation) {
return ((Operation) expr).reverse();
}
return new Not(expr);
}
Token not() {
return expr;
}
public <T> void appendSQL(SQLStatement stat, Query<T> query) {
// untested
stat.appendSQL("NOT(");
expr.appendSQL(stat, query);
stat.appendSQL(")");
}
}
/*
* Copyright 2004-2009 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 org.h2.jaqu.Query;
import org.h2.jaqu.SQLStatement;
import org.h2.jaqu.Token;
/**
* The Java 'null'.
*/
public class Null implements Token {
static final Null INSTANCE = new Null();
private Null() {
// don't allow to create new instances
}
public String toString() {
return "null";
}
public <T> void appendSQL(SQLStatement stat, Query<T> query) {
// untested
stat.appendSQL("NULL");
}
}
/*
* Copyright 2004-2009 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 org.h2.jaqu.Query;
import org.h2.jaqu.SQLStatement;
import org.h2.jaqu.Token;
/**
* A mathematical or comparison operation.
*/
class Operation implements Token {
/**
* The operation type.
*/
enum Type {
EQUALS("=") {
Type reverse() {
return NOT_EQUALS;
}
},
NOT_EQUALS("<>") {
Type reverse() {
return EQUALS;
}
},
BIGGER(">") {
Type reverse() {
return SMALLER_EQUALS;
}
},
BIGGER_EQUALS(">=") {
Type reverse() {
return SMALLER;
}
},
SMALLER_EQUALS("<=") {
Type reverse() {
return BIGGER;
}
},
SMALLER("<") {
Type reverse() {
return BIGGER_EQUALS;
}
},
ADD("+"),
SUBTRACT("-"),
MULTIPLY("*"),
DIVIDE("/"),
MOD("%");
private String name;
Type(String name) {
this.name = name;
}
public String toString() {
return name;
}
Type reverse() {
return null;
}
}
private final Token left, right;
private final Type op;
private Operation(Token left, Type op, Token right) {
this.left = left;
this.op = op;
this.right = right;
}
static Token get(Token left, Type op, Token right) {
if (op == Type.NOT_EQUALS && "0".equals(right.toString())) {
return left;
}
return new Operation(left, op, right);
}
public String toString() {
return left + " " + op + " " + right;
}
public Token reverse() {
return get(left, op.reverse(), right);
}
public <T> void appendSQL(SQLStatement stat, Query<T> query) {
left.appendSQL(stat, query);
stat.appendSQL(op.toString());
right.appendSQL(stat, query);
}
}
/*
* Copyright 2004-2009 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 org.h2.jaqu.Query;
import org.h2.jaqu.SQLStatement;
import org.h2.jaqu.Token;
/**
* An OR expression.
*/
public class Or implements Token {
private final Token left, right;
private Or(Token left, Token right) {
this.left = left;
this.right = right;
}
static Or get(Token left, Token right) {
return new Or(left, right);
}
public <T> void appendSQL(SQLStatement stat, Query<T> query) {
// untested
left.appendSQL(stat, query);
stat.appendSQL(" OR ");
right.appendSQL(stat, query);
}
}
/*
* Copyright 2004-2009 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 org.h2.jaqu.Query;
import org.h2.jaqu.SQLStatement;
import org.h2.jaqu.Token;
/**
* A variable.
*/
public class Variable implements Token {
static final Variable THIS = new Variable("this", null);
private final String name;
private final Object obj;
private Variable(String name, Object obj) {
this.name = name;
this.obj = obj;
}
static Variable get(String name, Object obj) {
return new Variable(name, obj);
}
public String toString() {
return name;
}
public <T> void appendSQL(SQLStatement stat, Query<T> query) {
query.appendSQL(stat, obj);
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论