@Override public void visit(ConstructMultiArrayInstruction insn) { Expr[] dimensionExprs = new Expr[insn.getDimensions().size()]; for (int i = 0; i < dimensionExprs.length; ++i) { dimensionExprs[i] = Expr.var(insn.getDimensions().get(i).getIndex()); } assign(Expr.createArray(insn.getItemType(), dimensionExprs), insn.getReceiver()); }
@Override public void visit(BinaryExpr expr) { switch (expr.getOperation()) { case AND: case OR: resultExpr = expr; return; default: break; } expr.getSecondOperand().acceptVisitor(this); Expr b = resultExpr; if (b instanceof ConstantExpr && expr.getOperation() == BinaryOperation.SUBTRACT) { if (tryMakePositive((ConstantExpr) b)) { expr.setOperation(BinaryOperation.ADD); } } expr.getFirstOperand().acceptVisitor(this); Expr a = resultExpr; Expr p = a; Expr q = b; boolean invert = false; if (isZero(p)) { Expr tmp = p; p = q; q = tmp; invert = true; } if (isComparison(p) && isZero(q)) { switch (expr.getOperation()) { case EQUALS: case NOT_EQUALS: case LESS: case LESS_OR_EQUALS: case GREATER: case GREATER_OR_EQUALS: { BinaryExpr comparison = (BinaryExpr) p; Expr result = BinaryExpr.binary( expr.getOperation(), comparison.getFirstOperand(), comparison.getSecondOperand()); result.setLocation(comparison.getLocation()); if (invert) { result = ExprOptimizer.invert(result); } resultExpr = result; return; } default: break; } } expr.setFirstOperand(a); expr.setSecondOperand(b); resultExpr = expr; }
@Override public void visit(AssignInstruction insn) { AssignmentStatement stmt = Statement.assign( Expr.var(insn.getReceiver().getIndex()), Expr.var(insn.getAssignee().getIndex())); stmt.getDebugNames().addAll(insn.getReceiver().getDebugNames()); stmt.setLocation(currentLocation); statements.add(stmt); }
@Override public void visit(NewMultiArrayExpr expr) { for (int i = 0; i < expr.getDimensions().size(); ++i) { Expr dimension = expr.getDimensions().get(i); dimension.acceptVisitor(this); expr.getDimensions().set(i, resultExpr); } resultExpr = expr; }
@Override public void visit(CloneArrayInstruction insn) { MethodDescriptor cloneMethodDesc = new MethodDescriptor("clone", ValueType.object("java.lang.Object")); MethodReference cloneMethod = new MethodReference("java.lang.Object", cloneMethodDesc); assign( Expr.invoke(cloneMethod, Expr.var(insn.getArray().getIndex()), new Expr[0]), insn.getReceiver()); }
@Override public void visit(WhileStatement statement) { if (statement.getBody().size() == 1 && statement.getBody().get(0) instanceof WhileStatement) { WhileStatement innerLoop = (WhileStatement) statement.getBody().get(0); BreakToContinueReplacer replacer = new BreakToContinueReplacer(innerLoop, statement); replacer.visitSequence(innerLoop.getBody()); statement.getBody().clear(); statement.getBody().addAll(innerLoop.getBody()); } List<Statement> statements = processSequence(statement.getBody()); for (int i = 0; i < statements.size(); ++i) { if (statements.get(i) instanceof ContinueStatement) { ContinueStatement continueStmt = (ContinueStatement) statements.get(i); if (continueStmt.getTarget() == statement) { statements.subList(i, statements.size()).clear(); break; } } } statement.getBody().clear(); statement.getBody().addAll(statements); if (statement.getCondition() != null) { List<Statement> sequenceBackup = resultSequence; resultSequence = new ArrayList<>(); statement.getCondition().acceptVisitor(this); statement.setCondition(resultExpr); resultSequence = sequenceBackup; } while (true) { if (!statement.getBody().isEmpty() && statement.getBody().get(0) instanceof ConditionalStatement) { ConditionalStatement cond = (ConditionalStatement) statement.getBody().get(0); if (cond.getConsequent().size() == 1 && cond.getConsequent().get(0) instanceof BreakStatement) { BreakStatement breakStmt = (BreakStatement) cond.getConsequent().get(0); if (breakStmt.getTarget() == statement) { statement.getBody().remove(0); if (statement.getCondition() != null) { Expr newCondition = Expr.binary( BinaryOperation.AND, statement.getCondition(), ExprOptimizer.invert(cond.getCondition())); newCondition.setLocation(statement.getCondition().getLocation()); statement.setCondition(newCondition); } else { statement.setCondition(ExprOptimizer.invert(cond.getCondition())); } continue; } } } break; } resultStmt = statement; }
@Override public void visit(PutElementInstruction insn) { AssignmentStatement stmt = Statement.assign( Expr.subscript( Expr.var(insn.getArray().getIndex()), Expr.var(insn.getIndex().getIndex())), Expr.var(insn.getValue().getIndex())); stmt.setLocation(currentLocation); statements.add(stmt); }
@Override public void visit(PutFieldInstruction insn) { Expr right = Expr.var(insn.getValue().getIndex()); Expr left; if (insn.getInstance() != null) { left = Expr.qualify(Expr.var(insn.getInstance().getIndex()), insn.getField()); } else { left = Expr.qualify(null, insn.getField()); } AssignmentStatement stmt = Statement.assign(left, right); stmt.setLocation(currentLocation); statements.add(stmt); }
@Override public void visit(MonitorExitInstruction insn) { MonitorExitStatement stmt = new MonitorExitStatement(); stmt.setLocation(currentLocation); stmt.setObjectRef(Expr.var(insn.getObjectRef().getIndex())); statements.add(stmt); }
@Override public void visit(RaiseInstruction insn) { ThrowStatement stmt = new ThrowStatement(); stmt.setLocation(currentLocation); stmt.setException(Expr.var(insn.getException().getIndex())); statements.add(stmt); }
@Override public void visit(ExitInstruction insn) { ReturnStatement stmt = Statement.exitFunction( insn.getValueToReturn() != null ? Expr.var(insn.getValueToReturn().getIndex()) : null); stmt.setLocation(currentLocation); statements.add(stmt); }
@Override public void visit(GetFieldInstruction insn) { if (insn.getInstance() != null) { AssignmentStatement stmt = Statement.assign( Expr.var(insn.getReceiver().getIndex()), Expr.qualify(Expr.var(insn.getInstance().getIndex()), insn.getField())); stmt.setLocation(currentLocation); statements.add(stmt); } else { Expr fieldExpr = Expr.qualify(null, insn.getField()); AssignmentStatement stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()), fieldExpr); stmt.setLocation(currentLocation); statements.add(stmt); } }
@Override public void visit(InvokeInstruction insn) { Expr[] exprArgs = new Expr[insn.getMethod().getParameterTypes().length]; for (int i = 0; i < insn.getArguments().size(); ++i) { exprArgs[i] = Expr.var(insn.getArguments().get(i).getIndex()); } InvocationExpr invocationExpr; if (insn.getInstance() != null) { if (insn.getType() == InvocationType.VIRTUAL) { invocationExpr = Expr.invoke(insn.getMethod(), Expr.var(insn.getInstance().getIndex()), exprArgs); } else { invocationExpr = Expr.invokeSpecial(insn.getMethod(), Expr.var(insn.getInstance().getIndex()), exprArgs); } } else { invocationExpr = Expr.invokeStatic(insn.getMethod(), exprArgs); } AssignmentStatement stmt; if (insn.getReceiver() != null) { stmt = Statement.assign(Expr.var(insn.getReceiver().getIndex()), invocationExpr); stmt.getDebugNames().addAll(insn.getReceiver().getDebugNames()); } else { stmt = Statement.assign(null, invocationExpr); } stmt.setLocation(currentLocation); stmt.setAsync(async); async = false; statements.add(stmt); }
@Override public void visit(CastIntegerInstruction insn) { Expr value = Expr.var(insn.getValue().getIndex()); switch (insn.getDirection()) { case FROM_INTEGER: switch (insn.getTargetType()) { case BYTE: value = Expr.unary(UnaryOperation.INT_TO_BYTE, value); break; case SHORT: value = Expr.unary(UnaryOperation.INT_TO_SHORT, value); break; case CHARACTER: value = Expr.unary(UnaryOperation.INT_TO_CHAR, value); break; } break; case TO_INTEGER: break; } assign(value, insn.getReceiver()); }
@Override public void visit(BranchingInstruction insn) { switch (insn.getCondition()) { case EQUAL: branch( compare(BinaryOperation.EQUALS, insn.getOperand()), insn.getConsequent(), insn.getAlternative()); break; case NOT_EQUAL: branch( compare(BinaryOperation.NOT_EQUALS, insn.getOperand()), insn.getConsequent(), insn.getAlternative()); break; case GREATER: branch( compare(BinaryOperation.GREATER, insn.getOperand()), insn.getConsequent(), insn.getAlternative()); break; case GREATER_OR_EQUAL: branch( compare(BinaryOperation.GREATER_OR_EQUALS, insn.getOperand()), insn.getConsequent(), insn.getAlternative()); break; case LESS: branch( compare(BinaryOperation.LESS, insn.getOperand()), insn.getConsequent(), insn.getAlternative()); break; case LESS_OR_EQUAL: branch( compare(BinaryOperation.LESS_OR_EQUALS, insn.getOperand()), insn.getConsequent(), insn.getAlternative()); break; case NOT_NULL: branch( Expr.binary( BinaryOperation.STRICT_NOT_EQUALS, Expr.var(insn.getOperand().getIndex()), Expr.constant(null)), insn.getConsequent(), insn.getAlternative()); break; case NULL: branch( Expr.binary( BinaryOperation.STRICT_EQUALS, Expr.var(insn.getOperand().getIndex()), Expr.constant(null)), insn.getConsequent(), insn.getAlternative()); break; } }
@Override public void visit(CastNumberInstruction insn) { Expr value = Expr.var(insn.getValue().getIndex()); switch (insn.getTargetType()) { case INT: switch (insn.getSourceType()) { case DOUBLE: case FLOAT: value = castToInteger(value); break; case LONG: value = castLongToInt(value); break; default: break; } break; case LONG: switch (insn.getSourceType()) { case INT: value = castIntToLong(value); break; case FLOAT: case DOUBLE: value = castToLong(value); break; default: break; } break; case FLOAT: case DOUBLE: if (insn.getSourceType() == NumericOperandType.LONG) { value = castFromLong(value); } break; default: break; } assign(value, insn.getReceiver()); }
private boolean tryApplyConstructor(InvocationExpr expr) { if (!expr.getMethod().getName().equals("<init>")) { return false; } if (resultSequence == null || resultSequence.isEmpty()) { return false; } Statement last = resultSequence.get(resultSequence.size() - 1); if (!(last instanceof AssignmentStatement)) { return false; } AssignmentStatement assignment = (AssignmentStatement) last; if (!(assignment.getLeftValue() instanceof VariableExpr)) { return false; } VariableExpr var = (VariableExpr) assignment.getLeftValue(); if (!(expr.getArguments().get(0) instanceof VariableExpr)) { return false; } VariableExpr target = (VariableExpr) expr.getArguments().get(0); if (target.getIndex() != var.getIndex()) { return false; } if (!(assignment.getRightValue() instanceof NewExpr)) { return false; } NewExpr constructed = (NewExpr) assignment.getRightValue(); if (!constructed.getConstructedClass().equals(expr.getMethod().getClassName())) { return false; } Expr[] args = expr.getArguments().toArray(new Expr[0]); args = Arrays.copyOfRange(args, 1, args.length); InvocationExpr constructrExpr = Expr.constructObject(expr.getMethod(), args); constructrExpr.setLocation(expr.getLocation()); assignment.setRightValue(constructrExpr); readFrequencies[var.getIndex()]--; return true; }
@Override public void visit(SwitchInstruction insn) { SwitchStatement stmt = new SwitchStatement(); stmt.setId("sblock" + (lastSwitchId++)); stmt.setValue(Expr.var(insn.getCondition().getIndex())); Map<Integer, List<Integer>> switchMap = new HashMap<>(); for (int i = 0; i < insn.getEntries().size(); ++i) { SwitchTableEntry entry = insn.getEntries().get(i); List<Integer> conditions = switchMap.get(entry.getTarget().getIndex()); if (conditions == null) { conditions = new ArrayList<>(); switchMap.put(entry.getTarget().getIndex(), conditions); } conditions.add(entry.getCondition()); } List<Integer> targets = new ArrayList<>(switchMap.keySet()); Collections.sort(targets); for (int target : targets) { SwitchClause clause = new SwitchClause(); List<Integer> conditionList = switchMap.get(target); int[] conditions = new int[conditionList.size()]; for (int i = 0; i < conditionList.size(); ++i) { conditions[i] = conditionList.get(i); } clause.setConditions(conditions); Statement jumpStmt = generateJumpStatement(stmt, target); if (jumpStmt != null) { clause.getBody().add(jumpStmt); } stmt.getClauses().add(clause); } Statement breakStmt = generateJumpStatement(insn.getDefaultTarget()); if (breakStmt != null) { stmt.getDefaultClause().add(breakStmt); } statements.add(stmt); }
@Override public void visit(NegateInstruction insn) { switch (insn.getOperandType()) { case INT: assign( castToInteger( Expr.unary(UnaryOperation.NEGATE, Expr.var(insn.getOperand().getIndex()))), insn.getReceiver()); break; case LONG: assign( Expr.unary(UnaryOperation.NEGATE_LONG, Expr.var(insn.getOperand().getIndex())), insn.getReceiver()); break; default: assign( Expr.unary(UnaryOperation.NEGATE, Expr.var(insn.getOperand().getIndex())), insn.getReceiver()); break; } }
@Override public void visit(IsInstanceInstruction insn) { assign( Expr.instanceOf(Expr.var(insn.getValue().getIndex()), insn.getType()), insn.getReceiver()); }
private void assign(Expr source, Variable target) { AssignmentStatement stmt = Statement.assign(Expr.var(target.getIndex()), source); stmt.setLocation(currentLocation); stmt.getDebugNames().addAll(target.getDebugNames()); statements.add(stmt); }
private Expr castToInteger(Expr value) { return Expr.binary(BinaryOperation.BITWISE_OR, value, Expr.constant(0)); }
private void eliminateRedundantBreaks(List<Statement> statements, IdentifiedStatement exit) { if (statements.isEmpty()) { return; } Statement last = statements.get(statements.size() - 1); if (last instanceof BreakStatement && exit != null) { IdentifiedStatement target = ((BreakStatement) last).getTarget(); if (exit == target) { statements.remove(statements.size() - 1); } } if (statements.isEmpty()) { return; } for (int i = 0; i < statements.size(); ++i) { Statement stmt = statements.get(i); if (stmt instanceof ConditionalStatement) { ConditionalStatement cond = (ConditionalStatement) stmt; check_conditional: { last = cond.getConsequent().isEmpty() ? null : cond.getConsequent().get(cond.getConsequent().size() - 1); if (last instanceof BreakStatement) { BreakStatement breakStmt = (BreakStatement) last; if (exit != null && exit == breakStmt.getTarget()) { cond.getConsequent().remove(cond.getConsequent().size() - 1); List<Statement> remaining = statements.subList(i + 1, statements.size()); cond.getAlternative().addAll(remaining); remaining.clear(); break check_conditional; } } last = cond.getAlternative().isEmpty() ? null : cond.getAlternative().get(cond.getAlternative().size() - 1); if (last instanceof BreakStatement) { BreakStatement breakStmt = (BreakStatement) last; if (exit != null && exit == breakStmt.getTarget()) { cond.getAlternative().remove(cond.getAlternative().size() - 1); List<Statement> remaining = statements.subList(i + 1, statements.size()); cond.getConsequent().addAll(remaining); remaining.clear(); } } } if (i == statements.size() - 1) { eliminateRedundantBreaks(cond.getConsequent(), exit); eliminateRedundantBreaks(cond.getAlternative(), exit); } normalizeConditional(cond); if (cond.getConsequent().size() == 1 && cond.getConsequent().get(0) instanceof ConditionalStatement) { ConditionalStatement innerCond = (ConditionalStatement) cond.getConsequent().get(0); if (innerCond.getAlternative().isEmpty()) { if (cond.getAlternative().isEmpty()) { cond.getConsequent().clear(); cond.getConsequent().addAll(innerCond.getConsequent()); cond.setCondition( Expr.binary( BinaryOperation.AND, cond.getCondition(), innerCond.getCondition(), cond.getCondition().getLocation())); --i; } else if (cond.getAlternative().size() != 1 || !(cond.getAlternative().get(0) instanceof ConditionalStatement)) { cond.setCondition(ExprOptimizer.invert(cond.getCondition())); cond.getConsequent().clear(); cond.getConsequent().addAll(cond.getAlternative()); cond.getAlternative().clear(); cond.getAlternative().add(innerCond); --i; } } } } else if (stmt instanceof BlockStatement) { BlockStatement nestedBlock = (BlockStatement) stmt; eliminateRedundantBreaks(nestedBlock.getBody(), nestedBlock); } else if (stmt instanceof WhileStatement) { WhileStatement whileStmt = (WhileStatement) stmt; eliminateRedundantBreaks(whileStmt.getBody(), null); } else if (stmt instanceof SwitchStatement) { SwitchStatement switchStmt = (SwitchStatement) stmt; for (SwitchClause clause : switchStmt.getClauses()) { eliminateRedundantBreaks(clause.getBody(), null); } eliminateRedundantBreaks(switchStmt.getDefaultClause(), null); } } }
@Override public void visit(StringConstantInstruction insn) { assign(Expr.constant(insn.getConstant()), insn.getReceiver()); }
private Expr castLongToInt(Expr value) { return Expr.unary(UnaryOperation.LONG_TO_INT, value); }
private Expr castIntToLong(Expr value) { return Expr.unary(UnaryOperation.INT_TO_LONG, value); }
@Override public void visit(NullCheckInstruction insn) { assign( Expr.unary(UnaryOperation.NULL_CHECK, Expr.var(insn.getValue().getIndex())), insn.getReceiver()); }
private Expr compare(BinaryOperation op, Variable value) { Expr expr = Expr.binary(op, Expr.var(value.getIndex()), Expr.constant(0)); expr.setLocation(currentLocation); return expr; }
private void intBinary(int first, int second, Variable result, BinaryOperation op) { assign(castToInteger(Expr.binary(op, Expr.var(first), Expr.var(second))), result); }
private Expr castFromLong(Expr value) { return Expr.unary(UnaryOperation.LONG_TO_NUM, value); }