package org.enumerable.lambda.support.expression;
import static org.objectweb.asm.Type.*;
import japa.parser.JavaParser;
import japa.parser.ast.expr.*;
import japa.parser.ast.type.ClassOrInterfaceType;
import japa.parser.ast.type.PrimitiveType;
import japa.parser.ast.type.PrimitiveType.Primitive;
import japa.parser.ast.type.ReferenceType;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.objectweb.asm.Opcodes;
import org.objectweb.asm.Type;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.FieldInsnNode;
import org.objectweb.asm.tree.IincInsnNode;
import org.objectweb.asm.tree.IntInsnNode;
import org.objectweb.asm.tree.LdcInsnNode;
import org.objectweb.asm.tree.LocalVariableNode;
import org.objectweb.asm.tree.MethodInsnNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.TypeInsnNode;
import org.objectweb.asm.tree.VarInsnNode;
import org.objectweb.asm.tree.analysis.Analyzer;
import org.objectweb.asm.tree.analysis.AnalyzerException;
import org.objectweb.asm.tree.analysis.BasicInterpreter;
import org.objectweb.asm.tree.analysis.Frame;
import org.objectweb.asm.tree.analysis.Interpreter;
import org.objectweb.asm.tree.analysis.Value;
import org.objectweb.asm.util.AbstractVisitor;
/**
* This interpreter is a simple decompiler for methods with a single expression.
* It uses {@link JavaParser} as its target AST.
* <p>
* It is fully TDD in both good and bad ways, meaning that most things are here
* just to make the tests pass, and no deep analysis has gone into it.
* <p>
* This Interpreter started as a copy of {@link BasicInterpreter} by Eric
* Bruneton and Bing Ran.
*/
public class ExpressionInterpreter implements Opcodes, Interpreter {
static final PrimitiveType PRIMITIVE_BOOLEAN = new PrimitiveType(Primitive.Boolean);
static final PrimitiveType PRIMITIVE_INT = new PrimitiveType(Primitive.Int);
static final PrimitiveType PRIMITIVE_FLOAT = new PrimitiveType(Primitive.Float);
static final PrimitiveType PRIMITIVE_LONG = new PrimitiveType(Primitive.Long);
static final PrimitiveType PRIMITIVE_DOUBLE = new PrimitiveType(Primitive.Double);
static final PrimitiveType PRIMITIVE_CHAR = new PrimitiveType(Primitive.Char);
static final PrimitiveType PRIMITIVE_BYTE = new PrimitiveType(Primitive.Byte);
static final PrimitiveType PRIMITIVE_SHORT = new PrimitiveType(Primitive.Short);
LocalVariableNode[] parameters;
Frame currentFrame;
Analyzer analyzer;
MethodNode mn;
static class ExpressionValue implements Value {
Expression expression;
japa.parser.ast.type.Type type;
int size = 1;
ExpressionValue(japa.parser.ast.type.Type type, Expression expression) {
this.type = type;
this.expression = expression;
if (type instanceof PrimitiveType) {
Primitive primitive = ((PrimitiveType) type).getType();
size = primitive == Primitive.Long || primitive == Primitive.Double ? 2 : 1;
}
}
public int getSize() {
return size;
}
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((expression == null) ? 0 : expression.hashCode());
result = prime * result + ((type == null) ? 0 : type.hashCode());
return result;
}
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ExpressionValue other = (ExpressionValue) obj;
if (expression == null) {
if (other.expression != null)
return false;
} else if (!expression.equals(other.expression))
return false;
if (type == null) {
if (other.type != null)
return false;
} else if (!type.equals(other.type))
return false;
return true;
}
public String toString() {
return expression + " (" + type + ")";
}
}
ExpressionInterpreter(MethodNode mn, LocalVariableNode... parameters) {
this.mn = mn;
this.parameters = parameters;
}
Expression expression;
UnaryExpr iinc;
AssignExpr iincAssign;
ExpressionValue assign;
ConditionalExpr conditional;
boolean cmpConditional;
Set<Integer> returns = new HashSet<Integer>();
void setCurrentFrame(Frame frame) {
currentFrame = frame;
if (iinc != null) {
if (frame.getStackSize() > 0) {
ExpressionValue value = new ExpressionValue(PRIMITIVE_INT, iinc);
ExpressionValue previous = (ExpressionValue) frame.pop();
if (previous.type == PRIMITIVE_INT && previous.expression instanceof NameExpr) {
frame.push(value);
iinc = null;
} else {
frame.push(previous);
}
} else {
if (iinc.getOperator() == UnaryExpr.Operator.posIncrement)
iinc.setOperator(UnaryExpr.Operator.preIncrement);
else
iinc.setOperator(UnaryExpr.Operator.preDecrement);
}
}
if (iincAssign != null) {
if (frame.getStackSize() > 0) {
ExpressionValue value = new ExpressionValue(PRIMITIVE_INT, iincAssign);
ExpressionValue previous = (ExpressionValue) frame.pop();
if (previous.type == PRIMITIVE_INT && previous.expression instanceof NameExpr) {
frame.push(value);
iincAssign = null;
} else {
frame.push(previous);
}
}
}
if (assign != null) {
if (frame.getStackSize() > 0) {
frame.pop();
frame.push(assign);
assign = null;
}
}
}
void newControlFlowEdge(int insn, int successor) {
}
public Value newValue(final Type type) {
if (type == null)
return new ExpressionValue(null, null);
Expression value = null;
switch (type.getSort()) {
case Type.VOID:
return null;
case Type.BOOLEAN:
return new ExpressionValue(PRIMITIVE_BOOLEAN, value);
case Type.CHAR:
case Type.BYTE:
case Type.SHORT:
case Type.INT:
return new ExpressionValue(PRIMITIVE_INT, value);
case Type.FLOAT:
return new ExpressionValue(PRIMITIVE_FLOAT, value);
case Type.LONG:
return new ExpressionValue(PRIMITIVE_LONG, value);
case Type.DOUBLE:
return new ExpressionValue(PRIMITIVE_DOUBLE, value);
case Type.ARRAY:
case Type.OBJECT:
return new ExpressionValue(createClassOrInterfaceType(removeJavaLang(type.getClassName())), value);
default:
throw new Error("Internal error");
}
}
public Value newOperation(final AbstractInsnNode insn) throws AnalyzerException {
switch (insn.getOpcode()) {
case ACONST_NULL:
return new ExpressionValue(createClassOrInterfaceType(Object.class.getName()), new NullLiteralExpr());
case ICONST_M1:
return new ExpressionValue(PRIMITIVE_INT, new UnaryExpr(new IntegerLiteralExpr("1"),
UnaryExpr.Operator.negative));
case ICONST_0:
return new ExpressionValue(PRIMITIVE_INT, new IntegerLiteralExpr("0"));
case ICONST_1:
return new ExpressionValue(PRIMITIVE_INT, new IntegerLiteralExpr("1"));
case ICONST_2:
return new ExpressionValue(PRIMITIVE_INT, new IntegerLiteralExpr("2"));
case ICONST_3:
return new ExpressionValue(PRIMITIVE_INT, new IntegerLiteralExpr("3"));
case ICONST_4:
return new ExpressionValue(PRIMITIVE_INT, new IntegerLiteralExpr("4"));
case ICONST_5:
return new ExpressionValue(PRIMITIVE_INT, new IntegerLiteralExpr("5"));
case LCONST_0:
return new ExpressionValue(PRIMITIVE_LONG, new LongLiteralExpr("0L"));
case LCONST_1:
return new ExpressionValue(PRIMITIVE_LONG, new LongLiteralExpr("1L"));
case FCONST_0:
return new ExpressionValue(PRIMITIVE_FLOAT, new DoubleLiteralExpr("0.0f"));
case FCONST_1:
return new ExpressionValue(PRIMITIVE_FLOAT, new DoubleLiteralExpr("1.0f"));
case FCONST_2:
return new ExpressionValue(PRIMITIVE_FLOAT, new DoubleLiteralExpr("2.0f"));
case DCONST_0:
return new ExpressionValue(PRIMITIVE_DOUBLE, new DoubleLiteralExpr("0.0"));
case DCONST_1:
return new ExpressionValue(PRIMITIVE_DOUBLE, new DoubleLiteralExpr("1.0"));
case BIPUSH:
case SIPUSH:
int operand = ((IntInsnNode) insn).operand;
if (operand < 0)
return new ExpressionValue(PRIMITIVE_INT, new UnaryExpr(new IntegerLiteralExpr(""
+ Math.abs(operand)), UnaryExpr.Operator.negative));
return new ExpressionValue(PRIMITIVE_INT, new IntegerLiteralExpr("" + operand));
case LDC:
Object cst = ((LdcInsnNode) insn).cst;
if (cst instanceof Number) {
ExpressionValue value = null;
if (cst instanceof Integer) {
value = new ExpressionValue(PRIMITIVE_INT, new IntegerLiteralExpr(cst.toString()));
} else if (cst instanceof Float) {
value = new ExpressionValue(PRIMITIVE_FLOAT, new DoubleLiteralExpr(cst.toString() + "f"));
} else if (cst instanceof Long) {
value = new ExpressionValue(PRIMITIVE_LONG, new LongLiteralExpr(cst.toString() + "L"));
} else if (cst instanceof Double) {
value = new ExpressionValue(PRIMITIVE_DOUBLE, new DoubleLiteralExpr(cst.toString()));
}
if (((Number) cst).intValue() < 0) {
StringLiteralExpr expr = (StringLiteralExpr) value.expression;
expr.setValue(expr.getValue().substring("-".length()));
value.expression = new UnaryExpr(expr, UnaryExpr.Operator.negative);
}
return value;
} else if (cst instanceof Type) {
ClassExpr classExpr = new ClassExpr(new ReferenceType(createClassOrInterfaceType(((Type) cst)
.getClassName())));
return new ExpressionValue(createClassOrInterfaceType(Class.class.getName()), classExpr);
} else {
return new ExpressionValue(createClassOrInterfaceType(String.class.getName()),
new StringLiteralExpr(cst.toString()));
}
case JSR:
throw new UnsupportedOperationException(AbstractVisitor.OPCODES[insn.getOpcode()]);
case GETSTATIC:
FieldInsnNode fieldNode = (FieldInsnNode) insn;
ExpressionValue getField = (ExpressionValue) newValue(getType(fieldNode.desc));
getField.expression = new FieldAccessExpr(new NameExpr(removeJavaLang(getObjectType(fieldNode.owner)
.getClassName())), fieldNode.name);
return getField;
case NEW:
return newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
default:
throw new Error("Internal error.");
}
}
ClassOrInterfaceType createClassOrInterfaceType(String className) {
if (!className.contains("."))
return new ClassOrInterfaceType(className);
ClassOrInterfaceType parent = null;
for (String name : className.split("\\."))
parent = new ClassOrInterfaceType(parent, name);
return parent;
}
LocalVariableNode getLocalVariable(int var) {
for (LocalVariableNode local : parameters)
if (var == local.index)
return local;
return null;
}
String removeJavaLang(String className) {
if (className.startsWith("java.lang."))
className = className.substring("java.lang.".length());
return className;
}
boolean isStoreInstruction(VarInsnNode vin) {
return vin.getOpcode() >= ISTORE && vin.getOpcode() <= ASTORE;
}
public Value copyOperation(final AbstractInsnNode insn, final Value value) throws AnalyzerException {
ExpressionValue expressionValue = (ExpressionValue) value;
if (insn instanceof VarInsnNode) {
VarInsnNode node = (VarInsnNode) insn;
if (isStoreInstruction(node)) {
AssignExpr.Operator op = AssignExpr.Operator.assign;
NameExpr target = new NameExpr(getLocalVariable(node.var).name);
Expression assignmentValue = expressionValue.expression;
if (expressionValue.expression instanceof BinaryExpr) {
BinaryExpr binary = (BinaryExpr) expressionValue.expression;
if (binary.getLeft().equals(target)) {
if (binary.getOperator() == BinaryExpr.Operator.plus)
op = AssignExpr.Operator.plus;
if (binary.getOperator() == BinaryExpr.Operator.minus)
op = AssignExpr.Operator.minus;
if (binary.getOperator() == BinaryExpr.Operator.times)
op = AssignExpr.Operator.star;
if (binary.getOperator() == BinaryExpr.Operator.divide)
op = AssignExpr.Operator.slash;
if (binary.getOperator() == BinaryExpr.Operator.binAnd)
op = AssignExpr.Operator.and;
if (binary.getOperator() == BinaryExpr.Operator.binOr)
op = AssignExpr.Operator.or;
if (binary.getOperator() == BinaryExpr.Operator.xor)
op = AssignExpr.Operator.xor;
if (binary.getOperator() == BinaryExpr.Operator.remainder)
op = AssignExpr.Operator.rem;
if (binary.getOperator() == BinaryExpr.Operator.lShift)
op = AssignExpr.Operator.lShift;
if (binary.getOperator() == BinaryExpr.Operator.rSignedShift)
op = AssignExpr.Operator.rSignedShift;
if (binary.getOperator() == BinaryExpr.Operator.rUnsignedShift)
op = AssignExpr.Operator.rUnsignedShift;
if (op != AssignExpr.Operator.assign)
assignmentValue = binary.getRight();
}
}
if (expressionValue.expression instanceof UnaryExpr)
assign = expressionValue;
else
assign = new ExpressionValue(expressionValue.type, new AssignExpr(target, assignmentValue, op));
} else {
if (node.var == 0)
return new ExpressionValue(expressionValue.type, new ThisExpr());
return new ExpressionValue(expressionValue.type, new NameExpr(getLocalVariable(node.var).name));
}
}
if (expressionValue.expression == null)
return expressionValue;
return new ExpressionValue(expressionValue.type, LambdaExpressionTrees
.parseExpression(expressionValue.expression.toString()));
}
public Value unaryOperation(final AbstractInsnNode insn, final Value value) throws AnalyzerException {
ExpressionValue expressionValue = (ExpressionValue) value;
switch (insn.getOpcode()) {
case INEG:
return new ExpressionValue(PRIMITIVE_INT, new UnaryExpr(expressionValue.expression,
UnaryExpr.Operator.negative));
case IINC:
IincInsnNode node = (IincInsnNode) insn;
NameExpr nameExpr = new NameExpr(getLocalVariable(node.var).name);
if (node.incr == 1)
iinc = new UnaryExpr(nameExpr, UnaryExpr.Operator.posIncrement);
if (node.incr == -1)
iinc = new UnaryExpr(nameExpr, UnaryExpr.Operator.posDecrement);
if (node.incr > 1)
iincAssign = new AssignExpr(nameExpr, new IntegerLiteralExpr(node.incr + ""),
AssignExpr.Operator.plus);
if (node.incr < -1)
iincAssign = new AssignExpr(nameExpr, new IntegerLiteralExpr(-node.incr + ""),
AssignExpr.Operator.minus);
return value;
case L2I:
case F2I:
case D2I:
return new ExpressionValue(PRIMITIVE_INT, new CastExpr(PRIMITIVE_INT, expressionValue.expression));
case I2B:
return new ExpressionValue(PRIMITIVE_BYTE, new CastExpr(PRIMITIVE_BYTE, expressionValue.expression));
case I2C:
return new ExpressionValue(PRIMITIVE_CHAR, new CastExpr(PRIMITIVE_CHAR, expressionValue.expression));
case I2S:
return new ExpressionValue(PRIMITIVE_SHORT, new CastExpr(PRIMITIVE_SHORT, expressionValue.expression));
case FNEG:
return new ExpressionValue(PRIMITIVE_FLOAT, new UnaryExpr(expressionValue.expression,
UnaryExpr.Operator.negative));
case I2F:
case L2F:
case D2F:
return new ExpressionValue(PRIMITIVE_FLOAT, new CastExpr(PRIMITIVE_FLOAT, expressionValue.expression));
case LNEG:
return new ExpressionValue(PRIMITIVE_LONG, new UnaryExpr(expressionValue.expression,
UnaryExpr.Operator.negative));
case I2L:
case F2L:
case D2L:
return new ExpressionValue(PRIMITIVE_LONG, new CastExpr(PRIMITIVE_LONG, expressionValue.expression));
case DNEG:
return new ExpressionValue(PRIMITIVE_DOUBLE, new UnaryExpr(expressionValue.expression,
UnaryExpr.Operator.negative));
case I2D:
case L2D:
case F2D:
return new ExpressionValue(PRIMITIVE_DOUBLE, new CastExpr(PRIMITIVE_DOUBLE, expressionValue.expression));
case IFEQ:
if (conditional != null) {
if (conditional.getCondition() instanceof BinaryExpr && cmpConditional) {
((BinaryExpr) conditional.getCondition()).setOperator(BinaryExpr.Operator.notEquals);
cmpConditional = false;
} else {
handleNestedConditional(expressionValue.expression);
}
} else {
conditional = new ConditionalExpr(expressionValue.expression, null, null);
}
return null;
case IFNE:
if (conditional != null) {
if (conditional.getCondition() instanceof BinaryExpr && cmpConditional) {
((BinaryExpr) conditional.getCondition()).setOperator(BinaryExpr.Operator.equals);
cmpConditional = false;
} else {
handleNestedConditional(new UnaryExpr(expressionValue.expression, UnaryExpr.Operator.not));
}
} else {
conditional = new ConditionalExpr(
new UnaryExpr(expressionValue.expression, UnaryExpr.Operator.not), null, null);
}
return null;
case IFGT:
((BinaryExpr) conditional.getCondition()).setOperator(BinaryExpr.Operator.lessEquals);
cmpConditional = false;
return null;
case IFLE:
((BinaryExpr) conditional.getCondition()).setOperator(BinaryExpr.Operator.greater);
cmpConditional = false;
return null;
case IFLT:
((BinaryExpr) conditional.getCondition()).setOperator(BinaryExpr.Operator.greaterEquals);
cmpConditional = false;
return null;
case IFGE:
((BinaryExpr) conditional.getCondition()).setOperator(BinaryExpr.Operator.less);
cmpConditional = false;
return null;
case TABLESWITCH:
case LOOKUPSWITCH:
throw new UnsupportedOperationException(AbstractVisitor.OPCODES[insn.getOpcode()]);
case IRETURN:
case LRETURN:
case FRETURN:
case DRETURN:
case ARETURN:
return null;
case PUTSTATIC:
FieldInsnNode fieldNode = (FieldInsnNode) insn;
ExpressionValue putField = (ExpressionValue) newValue(getType(fieldNode.desc));
putField.expression = new AssignExpr(new FieldAccessExpr(new NameExpr(removeJavaLang(getObjectType(
fieldNode.owner).getClassName())), fieldNode.name), expressionValue.expression,
AssignExpr.Operator.assign);
assign = putField;
return null;
case GETFIELD:
fieldNode = (FieldInsnNode) insn;
ExpressionValue getField = (ExpressionValue) newValue(Type.getType(fieldNode.desc));
getField.expression = new FieldAccessExpr(expressionValue.expression, fieldNode.name);
return getField;
case NEWARRAY:
PrimitiveType type;
switch (((IntInsnNode) insn).operand) {
case T_BOOLEAN:
type = PRIMITIVE_BOOLEAN;
break;
case T_CHAR:
type = PRIMITIVE_CHAR;
break;
case T_BYTE:
type = PRIMITIVE_BYTE;
break;
case T_SHORT:
type = PRIMITIVE_SHORT;
break;
case T_INT:
type = PRIMITIVE_INT;
break;
case T_FLOAT:
type = PRIMITIVE_FLOAT;
break;
case T_DOUBLE:
type = PRIMITIVE_DOUBLE;
break;
case T_LONG:
type = PRIMITIVE_LONG;
break;
default:
throw new AnalyzerException(insn, "Invalid array type");
}
ArrayList<Expression> dimensions = new ArrayList<Expression>();
dimensions.add(expressionValue.expression);
return new ExpressionValue(new ReferenceType(type, 1), new ArrayCreationExpr(type, dimensions, 0));
case ANEWARRAY:
ExpressionValue newArray = (ExpressionValue) newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
dimensions = new ArrayList<Expression>();
dimensions.add(expressionValue.expression);
newArray.expression = new ArrayCreationExpr(newArray.type, dimensions, 0);
return newArray;
case ARRAYLENGTH:
return new ExpressionValue(PRIMITIVE_INT, new FieldAccessExpr(expressionValue.expression, "length"));
case ATHROW:
throw new UnsupportedOperationException(AbstractVisitor.OPCODES[insn.getOpcode()]);
case CHECKCAST:
ExpressionValue cast = (ExpressionValue) newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
cast.expression = new CastExpr(new ReferenceType(cast.type), expressionValue.expression);
return cast;
case INSTANCEOF:
ExpressionValue instanceOf = (ExpressionValue) newValue(Type.getObjectType(((TypeInsnNode) insn).desc));
instanceOf.expression = new InstanceOfExpr(expressionValue.expression, new ReferenceType(instanceOf.type));
return instanceOf;
case MONITORENTER:
case MONITOREXIT:
throw new UnsupportedOperationException(AbstractVisitor.OPCODES[insn.getOpcode()]);
case IFNULL:
handleNestedConditional(new BinaryExpr(expressionValue.expression, new NullLiteralExpr(),
BinaryExpr.Operator.notEquals));
return null;
case IFNONNULL:
handleNestedConditional(new BinaryExpr(expressionValue.expression, new NullLiteralExpr(),
BinaryExpr.Operator.equals));
return null;
default:
throw new Error("Internal error.");
}
}
public Value binaryOperation(final AbstractInsnNode insn, final Value value1, final Value value2)
throws AnalyzerException {
ExpressionValue expressionValue1 = (ExpressionValue) value1;
ExpressionValue expressionValue2 = (ExpressionValue) value2;
switch (insn.getOpcode()) {
case IALOAD:
return new ExpressionValue(PRIMITIVE_INT, new ArrayAccessExpr(expressionValue1.expression,
expressionValue2.expression));
case BALOAD:
return new ExpressionValue(PRIMITIVE_BYTE, new ArrayAccessExpr(expressionValue1.expression,
expressionValue2.expression));
case CALOAD:
return new ExpressionValue(PRIMITIVE_CHAR, new ArrayAccessExpr(expressionValue1.expression,
expressionValue2.expression));
case SALOAD:
return new ExpressionValue(PRIMITIVE_SHORT, new ArrayAccessExpr(expressionValue1.expression,
expressionValue2.expression));
case IADD:
return new ExpressionValue(PRIMITIVE_INT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.plus));
case ISUB:
return new ExpressionValue(PRIMITIVE_INT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.minus));
case IMUL:
return new ExpressionValue(PRIMITIVE_INT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.times));
case IDIV:
return new ExpressionValue(PRIMITIVE_INT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.divide));
case IREM:
return new ExpressionValue(PRIMITIVE_INT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.remainder));
case ISHL:
return new ExpressionValue(PRIMITIVE_INT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.lShift));
case ISHR:
return new ExpressionValue(PRIMITIVE_INT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.rSignedShift));
case IUSHR:
return new ExpressionValue(PRIMITIVE_INT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.rUnsignedShift));
case IAND:
return new ExpressionValue(PRIMITIVE_INT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.binAnd));
case IOR:
return new ExpressionValue(PRIMITIVE_INT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.binOr));
case IXOR:
if (expressionValue2.expression.toString().equals("-1"))
return new ExpressionValue(PRIMITIVE_INT, new UnaryExpr(expressionValue1.expression,
UnaryExpr.Operator.inverse));
return new ExpressionValue(PRIMITIVE_INT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.xor));
case FALOAD:
return new ExpressionValue(PRIMITIVE_FLOAT, new ArrayAccessExpr(expressionValue1.expression,
expressionValue2.expression));
case FADD:
return new ExpressionValue(PRIMITIVE_FLOAT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.plus));
case FSUB:
return new ExpressionValue(PRIMITIVE_FLOAT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.minus));
case FMUL:
return new ExpressionValue(PRIMITIVE_FLOAT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.times));
case FDIV:
return new ExpressionValue(PRIMITIVE_FLOAT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.divide));
case FREM:
return new ExpressionValue(PRIMITIVE_FLOAT, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.remainder));
case LALOAD:
return new ExpressionValue(PRIMITIVE_LONG, new ArrayAccessExpr(expressionValue1.expression,
expressionValue2.expression));
case LADD:
return new ExpressionValue(PRIMITIVE_LONG, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.plus));
case LSUB:
return new ExpressionValue(PRIMITIVE_LONG, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.minus));
case LMUL:
return new ExpressionValue(PRIMITIVE_LONG, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.times));
case LDIV:
return new ExpressionValue(PRIMITIVE_LONG, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.divide));
case LREM:
return new ExpressionValue(PRIMITIVE_LONG, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.remainder));
case LSHL:
return new ExpressionValue(PRIMITIVE_LONG, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.lShift));
case LSHR:
return new ExpressionValue(PRIMITIVE_LONG, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.rSignedShift));
case LUSHR:
return new ExpressionValue(PRIMITIVE_LONG, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.rUnsignedShift));
case LAND:
return new ExpressionValue(PRIMITIVE_LONG, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.binAnd));
case LOR:
return new ExpressionValue(PRIMITIVE_LONG, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.binOr));
case LXOR:
if (expressionValue2.expression.toString().equals("-1L"))
return new ExpressionValue(PRIMITIVE_LONG, new UnaryExpr(expressionValue1.expression,
UnaryExpr.Operator.inverse));
return new ExpressionValue(PRIMITIVE_LONG, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.xor));
case DALOAD:
return new ExpressionValue(PRIMITIVE_DOUBLE, new ArrayAccessExpr(expressionValue1.expression,
expressionValue2.expression));
case DADD:
return new ExpressionValue(PRIMITIVE_DOUBLE, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.plus));
case DSUB:
return new ExpressionValue(PRIMITIVE_DOUBLE, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.minus));
case DMUL:
return new ExpressionValue(PRIMITIVE_DOUBLE, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.times));
case DDIV:
return new ExpressionValue(PRIMITIVE_DOUBLE, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.divide));
case DREM:
return new ExpressionValue(PRIMITIVE_DOUBLE, new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.remainder));
case AALOAD:
return new ExpressionValue(expressionValue1.type, new ArrayAccessExpr(expressionValue1.expression,
expressionValue2.expression));
case LCMP:
case FCMPL:
case FCMPG:
case DCMPL:
case DCMPG:
cmpConditional = true;
conditional = new ConditionalExpr(new BinaryExpr(expressionValue1.expression,
expressionValue2.expression, BinaryExpr.Operator.notEquals), null, null);
return new ExpressionValue(PRIMITIVE_INT, null);
case IF_ICMPEQ:
Expression condition = null;
if (booleanValue(expressionValue2.expression, expressionValue1).toString().equals("true"))
condition = new UnaryExpr(expressionValue1.expression, UnaryExpr.Operator.not);
else if (booleanValue(expressionValue1.expression, expressionValue2).toString().equals("true"))
condition = new UnaryExpr(expressionValue2.expression, UnaryExpr.Operator.not);
else if (booleanValue(expressionValue1.expression, expressionValue2).toString().equals("false"))
condition = expressionValue2.expression;
else
condition = new BinaryExpr(expressionValue1.expression, expressionValue2.expression,
BinaryExpr.Operator.notEquals);
handleNestedConditional(condition);
return null;
case IF_ICMPNE:
condition = null;
if (booleanValue(expressionValue2.expression, expressionValue1).toString().equals("true"))
condition = expressionValue1.expression;
else if (booleanValue(expressionValue1.expression, expressionValue2).toString().equals("true"))
condition = expressionValue2.expression;
else if (booleanValue(expressionValue1.expression, expressionValue2).toString().equals("false"))
condition = new UnaryExpr(expressionValue2.expression, UnaryExpr.Operator.not);
else
condition = new BinaryExpr(expressionValue1.expression, expressionValue2.expression,
BinaryExpr.Operator.equals);
handleNestedConditional(condition);
return null;
case IF_ICMPLT:
handleNestedConditional(new BinaryExpr(expressionValue1.expression, expressionValue2.expression,
BinaryExpr.Operator.greaterEquals));
return null;
case IF_ICMPGE:
handleNestedConditional(new BinaryExpr(expressionValue1.expression, expressionValue2.expression,
BinaryExpr.Operator.less));
return null;
case IF_ICMPGT:
handleNestedConditional(new BinaryExpr(expressionValue1.expression, expressionValue2.expression,
BinaryExpr.Operator.lessEquals));
return null;
case IF_ICMPLE:
handleNestedConditional(new BinaryExpr(expressionValue1.expression, expressionValue2.expression,
BinaryExpr.Operator.greater));
return null;
case IF_ACMPEQ:
handleNestedConditional(new BinaryExpr(expressionValue1.expression, expressionValue2.expression,
BinaryExpr.Operator.notEquals));
return null;
case IF_ACMPNE:
handleNestedConditional(new BinaryExpr(expressionValue1.expression, expressionValue2.expression,
BinaryExpr.Operator.equals));
return null;
case PUTFIELD:
FieldInsnNode fieldNode = (FieldInsnNode) insn;
ExpressionValue putField = (ExpressionValue) newValue(Type.getType(fieldNode.desc));
putField.expression = new AssignExpr(new FieldAccessExpr(expressionValue1.expression, fieldNode.name),
expressionValue2.expression, AssignExpr.Operator.assign);
assign = putField;
return null;
default:
throw new Error("Internal error.");
}
}
void handleNestedConditional(Expression condition) {
if (conditional == null)
conditional = new ConditionalExpr(condition, null, null);
else {
Expression currentCondition = conditional.getCondition();
if (currentCondition instanceof UnaryExpr
&& ((UnaryExpr) currentCondition).getOperator() == UnaryExpr.Operator.not) {
conditional.setCondition(new BinaryExpr(((UnaryExpr) currentCondition).getExpr(), condition,
BinaryExpr.Operator.or));
} else {
conditional.setCondition(new BinaryExpr(currentCondition, condition, BinaryExpr.Operator.and));
}
}
}
public Value ternaryOperation(final AbstractInsnNode insn, final Value value1, final Value value2,
final Value value3) throws AnalyzerException {
ExpressionValue expressionValue1 = (ExpressionValue) value1;
ExpressionValue expressionValue2 = (ExpressionValue) value2;
ExpressionValue expressionValue3 = (ExpressionValue) value3;
switch (insn.getOpcode()) {
case IASTORE:
case BASTORE:
case CASTORE:
case SASTORE:
case FASTORE:
case DASTORE:
case LASTORE:
case AASTORE:
if (expressionValue1.expression instanceof ArrayCreationExpr) {
ArrayCreationExpr arrayCreationExpression = (ArrayCreationExpr) expressionValue1.expression;
ArrayInitializerExpr initializer = arrayCreationExpression.getInitializer();
if (initializer == null)
initializer = new ArrayInitializerExpr();
List<Expression> values = initializer.getValues();
if (values == null)
values = new ArrayList<Expression>();
values.add(expressionValue3.expression);
initializer.setValues(values);
arrayCreationExpression.setInitializer(initializer);
arrayCreationExpression.setDimensions(null);
arrayCreationExpression.setArrayCount(1);
assign = expressionValue1;
} else {
assign = new ExpressionValue(expressionValue1.type, new AssignExpr(new ArrayAccessExpr(
expressionValue1.expression, expressionValue2.expression), expressionValue3.expression,
AssignExpr.Operator.assign));
}
return null;
default:
throw new Error("Internal error.");
}
}
@SuppressWarnings({ "rawtypes", "unchecked" })
public Value naryOperation(final AbstractInsnNode insn, final List values) throws AnalyzerException {
if (insn.getOpcode() == MULTIANEWARRAY) {
throw new UnsupportedOperationException(AbstractVisitor.OPCODES[insn.getOpcode()]);
} else {
MethodInsnNode node = (MethodInsnNode) insn;
ClassOrInterfaceType returnType = createClassOrInterfaceType(getReturnType(node.desc).getClassName());
Expression scope = null;
boolean isConstructor = node.getOpcode() == INVOKESPECIAL && "<init>".equals(node.name);
if (node.getOpcode() == INVOKESTATIC) {
String className = getObjectType(node.owner).getClassName();
scope = new NameExpr(removeJavaLang(className));
} else if (!isConstructor) {
ExpressionValue target = (ExpressionValue) values.remove(0);
if (!(target.expression instanceof ThisExpr))
scope = target.expression;
}
List<Expression> arguments = values.isEmpty() ? null : new ArrayList<Expression>();
for (ExpressionValue value : (List<ExpressionValue>) values)
arguments.add(value.expression);
if (isConstructor) {
arguments.remove(0);
ExpressionValue newExpressionValue = (ExpressionValue) values.remove(0);
ClassOrInterfaceType type = (ClassOrInterfaceType) newExpressionValue.type;
newExpressionValue.expression = new ObjectCreationExpr(scope, type, arguments.isEmpty() ? null
: arguments);
return new ExpressionValue(returnType, newExpressionValue.expression);
}
return new ExpressionValue(returnType, new MethodCallExpr(scope, node.name, arguments));
}
}
public void returnOperation(final AbstractInsnNode insn, final Value value, final Value expected)
throws AnalyzerException {
returns.add(mn.instructions.indexOf(insn));
expression = ((ExpressionValue) value).expression;
expression = booleanValue(expression, expected);
if (conditional != null) {
Expression elseExpr = conditional.getElseExpr();
if (elseExpr == null)
conditional.setElseExpr(expression);
else {
Expression condition = conditional.getCondition();
if (currentFrame.getStackSize() > 0) {
Value then = currentFrame.pop();
currentFrame.push(then);
conditional.setThenExpr(booleanValue(((ExpressionValue) then).expression, expected));
} else {
Expression thenExpr = conditional.getThenExpr();
if (thenExpr == null && expression != null)
conditional.setThenExpr(expression);
else
conditional.setThenExpr(new BooleanLiteralExpr(false));
}
Expression thenExpr = conditional.getThenExpr();
if (thenExpr instanceof BooleanLiteralExpr && elseExpr instanceof BooleanLiteralExpr) {
if (thenExpr.toString().equals("true") && elseExpr.toString().equals("false")) {
expression = condition;
} else if (thenExpr.toString().equals("false") && elseExpr.toString().equals("true")) {
if (condition instanceof BinaryExpr) {
BinaryExpr binaryExpr = (BinaryExpr) condition;
expression = condition;
if (binaryExpr.getLeft() instanceof BinaryExpr) {
BinaryExpr left = (BinaryExpr) binaryExpr.getLeft();
if (binaryExpr.getOperator() == BinaryExpr.Operator.and) {
binaryExpr.setOperator(BinaryExpr.Operator.or);
flipOperator(left);
}
}
if (couldBeECJ()) {
if (binaryExpr.getRight() instanceof BinaryExpr) {
BinaryExpr right = (BinaryExpr) binaryExpr.getRight();
if (binaryExpr.getOperator() == BinaryExpr.Operator.or)
flipOperator(right);
}
if (binaryExpr.getRight() instanceof UnaryExpr) {
UnaryExpr right = (UnaryExpr) binaryExpr.getRight();
if (right.getOperator() == UnaryExpr.Operator.not)
binaryExpr.setRight(right.getExpr());
}
}
} else
expression = new UnaryExpr(condition, UnaryExpr.Operator.not);
}
} else {
expression = conditional;
}
conditional = null;
}
}
}
boolean couldBeECJ() {
return returns.size() > 1;
}
BinaryExpr flipOperator(BinaryExpr binaryExpr) {
BinaryExpr.Operator op = binaryExpr.getOperator();
if (op == BinaryExpr.Operator.notEquals) {
binaryExpr.setOperator(BinaryExpr.Operator.equals);
} else if (op == BinaryExpr.Operator.equals) {
binaryExpr.setOperator(BinaryExpr.Operator.notEquals);
} else if (op == BinaryExpr.Operator.greater) {
binaryExpr.setOperator(BinaryExpr.Operator.lessEquals);
} else if (op == BinaryExpr.Operator.less) {
binaryExpr.setOperator(BinaryExpr.Operator.greaterEquals);
} else if (op == BinaryExpr.Operator.greaterEquals) {
binaryExpr.setOperator(BinaryExpr.Operator.less);
} else if (op == BinaryExpr.Operator.lessEquals) {
binaryExpr.setOperator(BinaryExpr.Operator.greater);
}
return binaryExpr;
}
Expression booleanValue(Expression expression, Value expected) {
if (((ExpressionValue) expected).type == PRIMITIVE_BOOLEAN && expression instanceof IntegerLiteralExpr)
if ("1".equals(expression.toString()))
expression = new BooleanLiteralExpr(true);
else if ("0".equals(expression.toString()))
expression = new BooleanLiteralExpr(false);
return expression;
}
public Value merge(final Value v, final Value w) {
if (!v.equals(w)) {
return new ExpressionValue(null, null);
}
return v;
}
}