diff --git a/shared-test-resources/miniTestSuite/java6/binary/LocalMerging.class b/shared-test-resources/miniTestSuite/java6/binary/LocalMerging.class new file mode 100644 index 00000000000..f908f52499a Binary files /dev/null and b/shared-test-resources/miniTestSuite/java6/binary/LocalMerging.class differ diff --git a/shared-test-resources/miniTestSuite/java6/source/LocalMerging.java b/shared-test-resources/miniTestSuite/java6/source/LocalMerging.java new file mode 100644 index 00000000000..873d6053e73 --- /dev/null +++ b/shared-test-resources/miniTestSuite/java6/source/LocalMerging.java @@ -0,0 +1,33 @@ +public class LocalMerging { + public void localMergingWithConstant(int n) { + String a = "one"; + // The branch returns either a local or a constant. + // Because of the divergence neither `a` nor `"two"` should be inlined, + // but a stack local variable should be created for holding the result of the branch. + System.out.println(n == 1 ? a : "two"); + } + + public void localMergingWithOtherLocal(int n) { + String a = "one"; + String b = "two"; + // The branch returns either a local or a different local. + // Because of the divergence neither `a` nor `b` should be inlined, + // but a stack local variable should be created for holding the result of the branch. + System.out.println(n == 1 ? a : b); + } + + public void localMergingWithDuplicateValue(int n) { + String a = "one"; + // One of the branches for the first argument contains the constant "two" + // and the second argument also contains the constant "two". + // This test ensures that when the first argument gets replaced by a stack local, + // the second argument isn't replaced as well. + System.setProperty(n == 1 ? a : "two", "two"); + } + + public void localMergingWithInlining(int n) { + String[] arr = new String[] {"a", "b"}; + int a = 1; + String b = arr[n == 1 ? 0 : a]; + } +} diff --git a/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java b/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java index 59623ce9a66..f1986b1d82c 100644 --- a/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java +++ b/sootup.core/src/main/java/sootup/core/jimple/visitor/ReplaceUseStmtVisitor.java @@ -71,6 +71,8 @@ public void caseInvokeStmt(@Nonnull JInvokeStmt stmt) { @Override public void caseAssignStmt(@Nonnull JAssignStmt stmt) { + // fall back to the original statement when none of the cases set a result + setResult(stmt); // uses on the def side.. e.g. a base in an JArrayRef but NOT with a simple Local! final Value leftOp = stmt.getLeftOp(); @@ -106,8 +108,6 @@ public void caseAssignStmt(@Nonnull JAssignStmt stmt) { if (exprVisitor.getResult() != rValue) { setResult(stmt.withRValue(exprVisitor.getResult())); } - } else { - setResult(stmt); } } diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java index 9e5f98859b3..72c45b3da82 100644 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java @@ -286,19 +286,7 @@ private String determineLocalName(int idx, boolean isField) { } void setStmt(@Nonnull AbstractInsnNode insn, @Nonnull Stmt stmt) { - Stmt overwrittenStmt = insnToStmt.put(insn, stmt); - if (overwrittenStmt != null) { - throw new IllegalArgumentException( - insn.getOpcode() + " already has an associated Stmt: " + overwrittenStmt); - } - } - - void mergeStmts(@Nonnull AbstractInsnNode insn, @Nonnull Stmt stmt) { - Stmt initiallyAssignedStmt = insnToStmt.put(insn, stmt); - if (initiallyAssignedStmt != null) { - Stmt merged = StmtContainer.getOrCreate(initiallyAssignedStmt, stmt); - insnToStmt.put(insn, merged); - } + insnToStmt.put(insn, stmt); } @Nonnull @@ -354,86 +342,52 @@ private void addReadOperandAssignments_internal(BiFunction= ICONST_M1 && op <= ICONST_5) { - v = IntConstant.getInstance(op - ICONST_0); - } else if (op == LCONST_0 || op == LCONST_1) { - v = LongConstant.getInstance(op - LCONST_0); - } else if (op >= FCONST_0 && op <= FCONST_2) { - v = FloatConstant.getInstance(op - FCONST_0); - } else if (op == DCONST_0 || op == DCONST_1) { - v = DoubleConstant.getInstance(op - DCONST_0); - } else { - throw new UnsupportedOperationException("Unknown constant opcode: " + op); - } - opr = new Operand(insn, v, this); - frame.setOut(opr); + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Value v; + if (op == ACONST_NULL) { + v = NullConstant.getInstance(); + } else if (op >= ICONST_M1 && op <= ICONST_5) { + v = IntConstant.getInstance(op - ICONST_0); + } else if (op == LCONST_0 || op == LCONST_1) { + v = LongConstant.getInstance(op - LCONST_0); + } else if (op >= FCONST_0 && op <= FCONST_2) { + v = FloatConstant.getInstance(op - FCONST_0); + } else if (op == DCONST_0 || op == DCONST_1) { + v = DoubleConstant.getInstance(op - DCONST_0); } else { - opr = out[0]; + throw new UnsupportedOperationException("Unknown constant opcode: " + op); } + Operand opr = new Operand(insn, v, this); + merging.mergeOutput(opr); if (op == LCONST_0 || op == LCONST_1 || op == DCONST_0 || op == DCONST_1) { operandStack.pushDual(opr); } else { @@ -492,22 +438,13 @@ private void convertConstInsn(@Nonnull InsnNode insn) { } private void convertArrayLoadInsn(@Nonnull InsnNode insn) { - StackFrame frame = operandStack.getOrCreateStackframe(insn); - Operand[] out = frame.getOut(); - Operand opr; - if (out == null) { - Operand indx = operandStack.popImmediate(); - Operand base = operandStack.popImmediate(); - JArrayRef ar = - JavaJimple.getInstance() - .newArrayRef((Local) base.stackOrValue(), (Immediate) indx.stackOrValue()); - opr = new Operand(insn, ar, this); - frame.setIn(indx, base); - frame.setOut(opr); - } else { - opr = out[0]; - frame.mergeIn(currentLineNumber, operandStack.pop(), operandStack.pop()); - } + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Operand indx = operandStack.pop(); + Operand base = operandStack.pop(); + merging.mergeInputs(indx, base); + JArrayRef ar = JavaJimple.getInstance().newArrayRef(base.toLocal(), indx.toImmediate()); + Operand opr = new Operand(insn, ar, this); + merging.mergeOutput(opr); int op = insn.getOpcode(); if (op == DALOAD || op == LALOAD) { operandStack.pushDual(opr); @@ -519,45 +456,21 @@ private void convertArrayLoadInsn(@Nonnull InsnNode insn) { private void convertArrayStoreInsn(@Nonnull InsnNode insn) { int op = insn.getOpcode(); boolean dword = op == LASTORE || op == DASTORE; - StackFrame frame = operandStack.getOrCreateStackframe(insn); - if (!insnToStmt.containsKey(insn)) { - Operand valueOp = dword ? operandStack.popImmediateDual() : operandStack.popImmediate(); - Operand indexOp = operandStack.popImmediate(); - Operand baseOp = operandStack.popLocal(); - JArrayRef ar = - JavaJimple.getInstance() - .newArrayRef((Local) baseOp.stackOrValue(), (Immediate) indexOp.stackOrValue()); - JAssignStmt as = Jimple.newAssignStmt(ar, valueOp.stackOrValue(), getStmtPositionInfo()); - frame.setIn(valueOp, indexOp, baseOp); - setStmt(insn, as); - valueOp.addUsageInStmt(as); - - } else { - frame.mergeIn( - currentLineNumber, - dword ? operandStack.popDual() : operandStack.pop(), - operandStack.pop(), - operandStack.pop()); - } + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Operand valueOp = dword ? operandStack.popDual() : operandStack.pop(); + Operand indexOp = operandStack.pop(); + Operand baseOp = operandStack.pop(); + merging.mergeInputs(valueOp, indexOp, baseOp); + JArrayRef ar = JavaJimple.getInstance().newArrayRef(baseOp.toLocal(), indexOp.toImmediate()); + JAssignStmt as = Jimple.newAssignStmt(ar, valueOp.toImmediate(), getStmtPositionInfo()); + setStmt(insn, as); } - /* - * Following version is more complex, using stack frames as opposed to simply swapping - */ - /* - * StackFrame frame = getFrame(insn); Operand[] out = frame.out(); Operand dup, dup2 = null, dupd, dupd2 = null; if (out == - * null) { dupd = popImmediate(); dup = new Operand(insn, dupd.stackOrValue()); if (dword) { dupd2 = peek(); if (dupd2 == - * DWORD_DUMMY) { pop(); dupd2 = dupd; } else { dupd2 = popImmediate(); } dup2 = new Operand(insn, dupd2.stackOrValue()); - * frame.out(dup, dup2); frame.in(dupd, dupd2); } else { frame.out(dup); frame.in(dupd); } } else { dupd = pop(); dup = - * out[0]; if (dword) { dupd2 = pop(); if (dupd2 == DWORD_DUMMY) dupd2 = dupd; dup2 = out[1]; frame.mergeIn(dupd, dupd2); } - * else { frame.mergeIn(dupd); } } - */ - private void convertDupInsn(@Nonnull InsnNode insn) { int op = insn.getOpcode(); // Get the top stack value which we need in either case - Operand dupd = operandStack.popImmediate(); + Operand dupd = operandStack.pop(); Operand dupd2 = null; // Some instructions allow operands that take two registers @@ -567,7 +480,7 @@ private void convertDupInsn(@Nonnull InsnNode insn) { operandStack.pop(); dupd2 = dupd; } else { - dupd2 = operandStack.popImmediate(); + dupd2 = operandStack.pop(); } } @@ -578,17 +491,15 @@ private void convertDupInsn(@Nonnull InsnNode insn) { } else if (op == DUP_X1) { // val2, val1 -> val1, val2, val1 // value1, value2 must not be of type double or long - Operand o2 = operandStack.popImmediate(); + Operand o2 = operandStack.pop(); operandStack.push(dupd); operandStack.push(o2); operandStack.push(dupd); } else if (op == DUP_X2) { // value3, value2, value1 -> value1, value3, value2, value1 - Operand o2 = operandStack.popImmediate(); - Operand o3 = - operandStack.peek() == Operand.DWORD_DUMMY - ? operandStack.pop() - : operandStack.popImmediate(); + Operand o2 = operandStack.pop(); + // pops either the `Operand.DWORD_DUMMY` or the third value + Operand o3 = operandStack.pop(); operandStack.push(dupd); operandStack.push(o3); operandStack.push(o2); @@ -602,7 +513,7 @@ private void convertDupInsn(@Nonnull InsnNode insn) { } else if (op == DUP2_X1) { // value3, value2, value1 -> value2, value1, value3, value2, value1 // Attention: value2 may be - Operand o2 = operandStack.popImmediate(); + Operand o2 = operandStack.pop(); operandStack.push(dupd2); operandStack.push(dupd); operandStack.push(o2); @@ -611,11 +522,8 @@ private void convertDupInsn(@Nonnull InsnNode insn) { } else if (op == DUP2_X2) { // (value4, value3), (value2, value1) -> (value2, value1), (value4, value3), // (value2, value1) - Operand o2 = operandStack.popImmediate(); - Operand o2h = - operandStack.peek() == Operand.DWORD_DUMMY - ? operandStack.pop() - : operandStack.popImmediate(); + Operand o2 = operandStack.pop(); + Operand o2h = operandStack.pop(); operandStack.push(dupd2); operandStack.push(dupd); operandStack.push(o2h); @@ -647,68 +555,51 @@ private void convertBinopInsn(@Nonnull InsnNode insn) { || op == LCMP || op == DCMPL || op == DCMPG; - StackFrame frame = operandStack.getOrCreateStackframe(insn); - Operand[] out = frame.getOut(); - Operand opr; - if (out == null) { - Operand op2 = - (dword && op != LSHL && op != LSHR && op != LUSHR) - ? operandStack.popImmediateDual() - : operandStack.popImmediate(); - Operand op1 = dword ? operandStack.popImmediateDual() : operandStack.popImmediate(); - Immediate v1 = (Immediate) op1.stackOrValue(); - Immediate v2 = (Immediate) op2.stackOrValue(); - AbstractBinopExpr binop; - if (op >= IADD && op <= DADD) { - binop = Jimple.newAddExpr(v1, v2); - } else if (op >= ISUB && op <= DSUB) { - binop = Jimple.newSubExpr(v1, v2); - } else if (op >= IMUL && op <= DMUL) { - binop = Jimple.newMulExpr(v1, v2); - } else if (op >= IDIV && op <= DDIV) { - binop = Jimple.newDivExpr(v1, v2); - } else if (op >= IREM && op <= DREM) { - binop = Jimple.newRemExpr(v1, v2); - } else if (op >= ISHL && op <= LSHL) { - binop = Jimple.newShlExpr(v1, v2); - } else if (op >= ISHR && op <= LSHR) { - binop = Jimple.newShrExpr(v1, v2); - } else if (op >= IUSHR && op <= LUSHR) { - binop = Jimple.newUshrExpr(v1, v2); - } else if (op >= IAND && op <= LAND) { - binop = Jimple.newAndExpr(v1, v2); - } else if (op >= IOR && op <= LOR) { - binop = Jimple.newOrExpr(v1, v2); - } else if (op >= IXOR && op <= LXOR) { - binop = Jimple.newXorExpr(v1, v2); - } else if (op == LCMP) { - binop = Jimple.newCmpExpr(v1, v2); - } else if (op == FCMPL || op == DCMPL) { - binop = Jimple.newCmplExpr(v1, v2); - } else if (op == FCMPG || op == DCMPG) { - binop = Jimple.newCmpgExpr(v1, v2); - } else { - throw new UnsupportedOperationException("Unknown binop: " + op); - } - opr = new Operand(insn, binop, this); - op1.addUsageInExpr(binop); - op2.addUsageInExpr(binop); - - frame.setIn(op2, op1); - frame.setOut(opr); + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Operand op2 = + (dword && op != LSHL && op != LSHR && op != LUSHR) + ? operandStack.popDual() + : operandStack.pop(); + Operand op1 = dword ? operandStack.popDual() : operandStack.pop(); + merging.mergeInputs(op2, op1); + Immediate v1 = op1.toImmediate(); + Immediate v2 = op2.toImmediate(); + AbstractBinopExpr binop; + if (op >= IADD && op <= DADD) { + binop = Jimple.newAddExpr(v1, v2); + } else if (op >= ISUB && op <= DSUB) { + binop = Jimple.newSubExpr(v1, v2); + } else if (op >= IMUL && op <= DMUL) { + binop = Jimple.newMulExpr(v1, v2); + } else if (op >= IDIV && op <= DDIV) { + binop = Jimple.newDivExpr(v1, v2); + } else if (op >= IREM && op <= DREM) { + binop = Jimple.newRemExpr(v1, v2); + } else if (op >= ISHL && op <= LSHL) { + binop = Jimple.newShlExpr(v1, v2); + } else if (op >= ISHR && op <= LSHR) { + binop = Jimple.newShrExpr(v1, v2); + } else if (op >= IUSHR && op <= LUSHR) { + binop = Jimple.newUshrExpr(v1, v2); + } else if (op >= IAND && op <= LAND) { + binop = Jimple.newAndExpr(v1, v2); + } else if (op >= IOR && op <= LOR) { + binop = Jimple.newOrExpr(v1, v2); + } else if (op >= IXOR && op <= LXOR) { + binop = Jimple.newXorExpr(v1, v2); + } else if (op == LCMP) { + binop = Jimple.newCmpExpr(v1, v2); + } else if (op == FCMPL || op == DCMPL) { + binop = Jimple.newCmplExpr(v1, v2); + } else if (op == FCMPG || op == DCMPG) { + binop = Jimple.newCmpgExpr(v1, v2); } else { - opr = out[0]; - if (dword) { - if (op != LSHL && op != LSHR && op != LUSHR) { - - frame.mergeIn(currentLineNumber, operandStack.popDual(), operandStack.popDual()); - } else { - frame.mergeIn(currentLineNumber, operandStack.pop(), operandStack.popDual()); - } - } else { - frame.mergeIn(currentLineNumber, operandStack.pop(), operandStack.pop()); - } + throw new UnsupportedOperationException("Unknown binop: " + op); } + + Operand opr = new Operand(insn, binop, this); + merging.mergeOutput(opr); + if (dword && op < LCMP) { operandStack.pushDual(opr); } else { @@ -719,28 +610,19 @@ private void convertBinopInsn(@Nonnull InsnNode insn) { private void convertUnopInsn(@Nonnull InsnNode insn) { int op = insn.getOpcode(); boolean dword = op == LNEG || op == DNEG; - StackFrame frame = operandStack.getOrCreateStackframe(insn); - Operand[] out = frame.getOut(); - Operand opr; - if (out == null) { - Operand op1 = dword ? operandStack.popImmediateDual() : operandStack.popImmediate(); - Value v1 = op1.stackOrValue(); - AbstractUnopExpr unop; - if (op >= INEG && op <= DNEG) { - unop = Jimple.newNegExpr((Immediate) v1); - } else if (op == ARRAYLENGTH) { - unop = Jimple.newLengthExpr((Immediate) v1); - } else { - throw new UnsupportedOperationException("Unknown unop: " + op); - } - op1.addUsageInExpr(unop); - opr = new Operand(insn, unop, this); - frame.setIn(op1); - frame.setOut(opr); + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Operand op1 = dword ? operandStack.popDual() : operandStack.pop(); + merging.mergeInputs(op1); + AbstractUnopExpr unop; + if (op >= INEG && op <= DNEG) { + unop = Jimple.newNegExpr(op1.toImmediate()); + } else if (op == ARRAYLENGTH) { + unop = Jimple.newLengthExpr(op1.toImmediate()); } else { - opr = out[0]; - frame.mergeIn(currentLineNumber, dword ? operandStack.popDual() : operandStack.pop()); + throw new UnsupportedOperationException("Unknown unop: " + op); } + Operand opr = new Operand(insn, unop, this); + merging.mergeOutput(opr); if (dword) { operandStack.pushDual(opr); } else { @@ -752,54 +634,46 @@ private void convertPrimCastInsn(@Nonnull InsnNode insn) { int op = insn.getOpcode(); boolean tod = op == I2L || op == I2D || op == F2L || op == F2D || op == D2L || op == L2D; boolean fromd = op == D2L || op == L2D || op == D2I || op == L2I || op == D2F || op == L2F; - StackFrame frame = operandStack.getOrCreateStackframe(insn); - Operand[] out = frame.getOut(); - Operand opr; - if (out == null) { - Type totype; - switch (op) { - case I2L: - case F2L: - case D2L: - totype = PrimitiveType.getLong(); - break; - case L2I: - case F2I: - case D2I: - totype = PrimitiveType.getInt(); - break; - case I2F: - case L2F: - case D2F: - totype = PrimitiveType.getFloat(); - break; - case I2D: - case L2D: - case F2D: - totype = PrimitiveType.getDouble(); - break; - case I2B: - totype = PrimitiveType.getByte(); - break; - case I2S: - totype = PrimitiveType.getShort(); - break; - case I2C: - totype = PrimitiveType.getChar(); - break; - default: - throw new IllegalStateException("Unknown prim cast op: " + op); - } - Operand val = fromd ? operandStack.popImmediateDual() : operandStack.popImmediate(); - JCastExpr cast = Jimple.newCastExpr((Immediate) val.stackOrValue(), totype); - opr = new Operand(insn, cast, this); - val.addUsageInExpr(cast); - frame.setIn(val); - frame.setOut(opr); - } else { - opr = out[0]; - frame.mergeIn(currentLineNumber, fromd ? operandStack.popDual() : operandStack.pop()); - } + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Type totype; + switch (op) { + case I2L: + case F2L: + case D2L: + totype = PrimitiveType.getLong(); + break; + case L2I: + case F2I: + case D2I: + totype = PrimitiveType.getInt(); + break; + case I2F: + case L2F: + case D2F: + totype = PrimitiveType.getFloat(); + break; + case I2D: + case L2D: + case F2D: + totype = PrimitiveType.getDouble(); + break; + case I2B: + totype = PrimitiveType.getByte(); + break; + case I2S: + totype = PrimitiveType.getShort(); + break; + case I2C: + totype = PrimitiveType.getChar(); + break; + default: + throw new IllegalStateException("Unknown prim cast op: " + op); + } + Operand val = fromd ? operandStack.popDual() : operandStack.pop(); + merging.mergeInputs(val); + JCastExpr cast = Jimple.newCastExpr(val.toImmediate(), totype); + Operand opr = new Operand(insn, cast, this); + merging.mergeOutput(opr); if (tod) { operandStack.pushDual(opr); } else { @@ -810,17 +684,11 @@ private void convertPrimCastInsn(@Nonnull InsnNode insn) { private void convertReturnInsn(@Nonnull InsnNode insn) { int op = insn.getOpcode(); boolean dword = op == LRETURN || op == DRETURN; - StackFrame frame = operandStack.getOrCreateStackframe(insn); - if (!insnToStmt.containsKey(insn)) { - Operand val = dword ? operandStack.popImmediateDual() : operandStack.popImmediate(); - JReturnStmt ret = Jimple.newReturnStmt((Immediate) val.stackOrValue(), getStmtPositionInfo()); - frame.setIn(val); - setStmt(insn, ret); - val.addUsageInStmt(ret); - } else { - final Operand operand = dword ? operandStack.popDual() : operandStack.pop(); - frame.mergeIn(currentLineNumber, operand); - } + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Operand val = dword ? operandStack.popDual() : operandStack.pop(); + merging.mergeInputs(val); + JReturnStmt ret = Jimple.newReturnStmt(val.toImmediate(), getStmtPositionInfo()); + setStmt(insn, ret); } private void convertInsn(@Nonnull InsnNode insn) { @@ -829,9 +697,7 @@ private void convertInsn(@Nonnull InsnNode insn) { /* * We can ignore NOP instructions, but for completeness, we handle them */ - if (!insnToStmt.containsKey(insn)) { - insnToStmt.put(insn, Jimple.newNopStmt(getStmtPositionInfo())); - } + setStmt(insn, Jimple.newNopStmt(getStmtPositionInfo())); } else if (op >= ACONST_NULL && op <= DCONST_1) { convertConstInsn(insn); } else if (op >= IALOAD && op <= SALOAD) { @@ -839,19 +705,16 @@ private void convertInsn(@Nonnull InsnNode insn) { } else if (op >= IASTORE && op <= SASTORE) { convertArrayStoreInsn(insn); } else if (op == POP) { - operandStack.popImmediate(); + operandStack.pop().emitStatement(); } else if (op == POP2) { - operandStack.popImmediate(); - if (operandStack.peek() == Operand.DWORD_DUMMY) { - operandStack.pop(); - } else { - operandStack.popImmediate(); - } + operandStack.pop().emitStatement(); + // pops the `Operand.DWORD_DUMMY` or the second value + operandStack.pop().emitStatement(); } else if (op >= DUP && op <= DUP2_X2) { convertDupInsn(insn); } else if (op == SWAP) { - Operand o1 = operandStack.popImmediate(); - Operand o2 = operandStack.popImmediate(); + Operand o1 = operandStack.pop(); + Operand o2 = operandStack.pop(); operandStack.push(o1); operandStack.push(o2); } else if ((op >= IADD && op <= DREM) @@ -865,38 +728,24 @@ private void convertInsn(@Nonnull InsnNode insn) { } else if (op >= IRETURN && op <= ARETURN) { convertReturnInsn(insn); } else if (op == RETURN) { - if (!insnToStmt.containsKey(insn)) { - setStmt(insn, Jimple.newReturnVoidStmt(getStmtPositionInfo())); - } + setStmt(insn, Jimple.newReturnVoidStmt(getStmtPositionInfo())); } else if (op == ATHROW) { - StackFrame frame = operandStack.getOrCreateStackframe(insn); - Operand opr; - if (!insnToStmt.containsKey(insn)) { - opr = operandStack.popImmediate(); - JThrowStmt ts = Jimple.newThrowStmt((Immediate) opr.stackOrValue(), getStmtPositionInfo()); - frame.setIn(opr); - frame.setOut(opr); - setStmt(insn, ts); - opr.addUsageInStmt(ts); - } else { - opr = operandStack.pop(); - frame.mergeIn(currentLineNumber, opr); - } + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Operand opr = operandStack.pop(); + merging.mergeInputs(opr); + JThrowStmt ts = Jimple.newThrowStmt(opr.toImmediate(), getStmtPositionInfo()); + setStmt(insn, ts); + merging.mergeOutput(opr); operandStack.push(opr); } else if (op == MONITORENTER || op == MONITOREXIT) { - StackFrame frame = operandStack.getOrCreateStackframe(insn); - if (!insnToStmt.containsKey(insn)) { - Operand opr = operandStack.popStackConst(); - Stmt ts = - op == MONITORENTER - ? Jimple.newEnterMonitorStmt((Immediate) opr.stackOrValue(), getStmtPositionInfo()) - : Jimple.newExitMonitorStmt((Immediate) opr.stackOrValue(), getStmtPositionInfo()); - frame.setIn(opr); - setStmt(insn, ts); - opr.addUsageInStmt(ts); - } else { - frame.mergeIn(currentLineNumber, operandStack.pop()); - } + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Operand opr = operandStack.popStackConst(); + merging.mergeInputs(opr); + Stmt ts = + op == MONITORENTER + ? Jimple.newEnterMonitorStmt(opr.toImmediate(), getStmtPositionInfo()) + : Jimple.newExitMonitorStmt(opr.toImmediate(), getStmtPositionInfo()); + setStmt(insn, ts); } else { throw new UnsupportedOperationException("Unknown insn op: " + op); } @@ -904,174 +753,135 @@ private void convertInsn(@Nonnull InsnNode insn) { private void convertIntInsn(@Nonnull IntInsnNode insn) { int op = insn.getOpcode(); - StackFrame frame = operandStack.getOrCreateStackframe(insn); - Operand[] out = frame.getOut(); - Operand opr; - if (out == null) { - Value v; - if (op == BIPUSH || op == SIPUSH) { - v = IntConstant.getInstance(insn.operand); - } else { - // assert(op == NEWARRAY) - Type type; - switch (insn.operand) { - case T_BOOLEAN: - type = PrimitiveType.getBoolean(); - break; - case T_CHAR: - type = PrimitiveType.getChar(); - break; - case T_FLOAT: - type = PrimitiveType.getFloat(); - break; - case T_DOUBLE: - type = PrimitiveType.getDouble(); - break; - case T_BYTE: - type = PrimitiveType.getByte(); - break; - case T_SHORT: - type = PrimitiveType.getShort(); - break; - case T_INT: - type = PrimitiveType.getInt(); - break; - case T_LONG: - type = PrimitiveType.getLong(); - break; - default: - throw new UnsupportedOperationException("Unknown NEWARRAY type!"); - } - Operand size = operandStack.popImmediate(); - JNewArrayExpr anew = - JavaJimple.getInstance().newNewArrayExpr(type, (Immediate) size.stackOrValue()); - size.addUsageInExpr(anew); - frame.setIn(size); - v = anew; - } - opr = new Operand(insn, v, this); - frame.setOut(opr); + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Value v; + if (op == BIPUSH || op == SIPUSH) { + v = IntConstant.getInstance(insn.operand); } else { - opr = out[0]; - if (op == NEWARRAY) { - frame.mergeIn(currentLineNumber, operandStack.pop()); + assert op == NEWARRAY; + Type type; + switch (insn.operand) { + case T_BOOLEAN: + type = PrimitiveType.getBoolean(); + break; + case T_CHAR: + type = PrimitiveType.getChar(); + break; + case T_FLOAT: + type = PrimitiveType.getFloat(); + break; + case T_DOUBLE: + type = PrimitiveType.getDouble(); + break; + case T_BYTE: + type = PrimitiveType.getByte(); + break; + case T_SHORT: + type = PrimitiveType.getShort(); + break; + case T_INT: + type = PrimitiveType.getInt(); + break; + case T_LONG: + type = PrimitiveType.getLong(); + break; + default: + throw new UnsupportedOperationException("Unknown NEWARRAY type!"); } + Operand size = operandStack.pop(); + merging.mergeInputs(size); + v = JavaJimple.getInstance().newNewArrayExpr(type, size.toImmediate()); } + Operand opr = new Operand(insn, v, this); + merging.mergeOutput(opr); operandStack.push(opr); } private void convertJumpInsn(@Nonnull JumpInsnNode insn) { int op = insn.getOpcode(); if (op == GOTO) { - if (!insnToStmt.containsKey(insn)) { - BranchingStmt gotoStmt = Jimple.newGotoStmt(getStmtPositionInfo()); - stmtsThatBranchToLabel.put(gotoStmt, insn.label); - setStmt(insn, gotoStmt); - } + BranchingStmt gotoStmt = Jimple.newGotoStmt(getStmtPositionInfo()); + stmtsThatBranchToLabel.put(gotoStmt, insn.label); + setStmt(insn, gotoStmt); return; } /* must be ifX insn */ - StackFrame frame = operandStack.getOrCreateStackframe(insn); - if (!insnToStmt.containsKey(insn)) { - Operand val = operandStack.popImmediate(); - Immediate v = (Immediate) val.stackOrValue(); - AbstractConditionExpr cond; - boolean isCmp = false; - Operand val1 = null; - - if (op >= IF_ICMPEQ && op <= IF_ACMPNE) { - isCmp = true; - val1 = operandStack.popImmediate(); - Immediate v1 = (Immediate) val1.stackOrValue(); - switch (op) { - case IF_ICMPEQ: - case IF_ACMPEQ: - cond = Jimple.newEqExpr(v1, v); - break; - case IF_ICMPNE: - case IF_ACMPNE: - cond = Jimple.newNeExpr(v1, v); - break; - case IF_ICMPLT: - cond = Jimple.newLtExpr(v1, v); - break; - case IF_ICMPGE: - cond = Jimple.newGeExpr(v1, v); - break; - case IF_ICMPGT: - cond = Jimple.newGtExpr(v1, v); - break; - case IF_ICMPLE: - cond = Jimple.newLeExpr(v1, v); - break; - default: - throw new UnsupportedOperationException("Unknown if op: " + op); - } - val1.addUsageInExpr(cond); - val.addUsageInExpr(cond); - frame.setIn(val, val1); - } else { - switch (op) { - case IFEQ: - cond = Jimple.newEqExpr(v, IntConstant.getInstance(0)); - break; - case IFNE: - cond = Jimple.newNeExpr(v, IntConstant.getInstance(0)); - break; - case IFLT: - cond = Jimple.newLtExpr(v, IntConstant.getInstance(0)); - break; - case IFGE: - cond = Jimple.newGeExpr(v, IntConstant.getInstance(0)); - break; - case IFGT: - cond = Jimple.newGtExpr(v, IntConstant.getInstance(0)); - break; - case IFLE: - cond = Jimple.newLeExpr(v, IntConstant.getInstance(0)); - break; - case IFNULL: - cond = Jimple.newEqExpr(v, NullConstant.getInstance()); - break; - case IFNONNULL: - cond = Jimple.newNeExpr(v, NullConstant.getInstance()); - break; - default: - throw new UnsupportedOperationException("Unknown if op: " + op); - } - val.addUsageInExpr(cond); - frame.setIn(val); - } - BranchingStmt ifStmt = Jimple.newIfStmt(cond, getStmtPositionInfo()); - stmtsThatBranchToLabel.put(ifStmt, insn.label); - setStmt(insn, ifStmt); - if (isCmp) { - val1.addUsageInStmt(ifStmt); + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Operand val = operandStack.pop(); + Immediate v = val.toImmediate(); + AbstractConditionExpr cond; + + if (op >= IF_ICMPEQ && op <= IF_ACMPNE) { + Operand val1 = operandStack.pop(); + merging.mergeInputs(val, val1); + Immediate v1 = val1.toImmediate(); + switch (op) { + case IF_ICMPEQ: + case IF_ACMPEQ: + cond = Jimple.newEqExpr(v1, v); + break; + case IF_ICMPNE: + case IF_ACMPNE: + cond = Jimple.newNeExpr(v1, v); + break; + case IF_ICMPLT: + cond = Jimple.newLtExpr(v1, v); + break; + case IF_ICMPGE: + cond = Jimple.newGeExpr(v1, v); + break; + case IF_ICMPGT: + cond = Jimple.newGtExpr(v1, v); + break; + case IF_ICMPLE: + cond = Jimple.newLeExpr(v1, v); + break; + default: + throw new UnsupportedOperationException("Unknown if op: " + op); } - - val.addUsageInStmt(ifStmt); } else { - if (op >= IF_ICMPEQ && op <= IF_ACMPNE) { - frame.mergeIn(currentLineNumber, operandStack.pop(), operandStack.pop()); - } else { - frame.mergeIn(currentLineNumber, operandStack.pop()); + merging.mergeInputs(val); + switch (op) { + case IFEQ: + cond = Jimple.newEqExpr(v, IntConstant.getInstance(0)); + break; + case IFNE: + cond = Jimple.newNeExpr(v, IntConstant.getInstance(0)); + break; + case IFLT: + cond = Jimple.newLtExpr(v, IntConstant.getInstance(0)); + break; + case IFGE: + cond = Jimple.newGeExpr(v, IntConstant.getInstance(0)); + break; + case IFGT: + cond = Jimple.newGtExpr(v, IntConstant.getInstance(0)); + break; + case IFLE: + cond = Jimple.newLeExpr(v, IntConstant.getInstance(0)); + break; + case IFNULL: + cond = Jimple.newEqExpr(v, NullConstant.getInstance()); + break; + case IFNONNULL: + cond = Jimple.newNeExpr(v, NullConstant.getInstance()); + break; + default: + throw new UnsupportedOperationException("Unknown if op: " + op); } } + BranchingStmt ifStmt = Jimple.newIfStmt(cond, getStmtPositionInfo()); + stmtsThatBranchToLabel.put(ifStmt, insn.label); + setStmt(insn, ifStmt); } private void convertLdcInsn(@Nonnull LdcInsnNode insn) { Object val = insn.cst; boolean dword = val instanceof Long || val instanceof Double; - StackFrame frame = operandStack.getOrCreateStackframe(insn); - Operand[] out = frame.getOut(); - Operand opr; - if (out == null) { - Value v = toSootValue(val); - opr = new Operand(insn, v, this); - frame.setOut(opr); - } else { - opr = out[0]; - } + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Value v = toSootValue(val); + Operand opr = new Operand(insn, v, this); + merging.mergeOutput(opr); if (dword) { operandStack.pushDual(opr); } else { @@ -1131,8 +941,8 @@ private JFieldRef toSootFieldRef(Handle methodHandle) { || kind == MethodHandle.Kind.REF_PUT_FIELD_STATIC.getValue()) { return Jimple.newStaticFieldRef(fieldSignature); } else { - Operand base = operandStack.popLocal(); - return Jimple.newInstanceFieldRef((Local) base.stackOrValue(), fieldSignature); + Operand base = operandStack.pop(); + return Jimple.newInstanceFieldRef(base.toLocal(), fieldSignature); } } @@ -1153,151 +963,96 @@ private MethodSignature toMethodSignature(Handle methodHandle) { } private void convertLookupSwitchInsn(@Nonnull LookupSwitchInsnNode insn) { - StackFrame frame = operandStack.getOrCreateStackframe(insn); + OperandMerging merging = operandStack.getOrCreateMerging(insn); if (insnToStmt.containsKey(insn)) { - frame.mergeIn(currentLineNumber, operandStack.pop()); + merging.mergeInputs(operandStack.pop()); return; } - Operand key = operandStack.popImmediate(); + Operand key = operandStack.pop(); + merging.mergeInputs(key); List keys = new ArrayList<>(insn.keys.size()); for (Integer i : insn.keys) { keys.add(IntConstant.getInstance(i)); } JSwitchStmt lookupSwitchStmt = - Jimple.newLookupSwitchStmt((Immediate) key.stackOrValue(), keys, getStmtPositionInfo()); + Jimple.newLookupSwitchStmt(key.toImmediate(), keys, getStmtPositionInfo()); // uphold insertion order! stmtsThatBranchToLabel.putAll(lookupSwitchStmt, insn.labels); stmtsThatBranchToLabel.put(lookupSwitchStmt, insn.dflt); - frame.setIn(key); setStmt(insn, lookupSwitchStmt); - key.addUsageInStmt(lookupSwitchStmt); } private void convertMethodInsn(@Nonnull MethodInsnNode insn) { - int op = insn.getOpcode(); boolean isInstance = op != INVOKESTATIC; - StackFrame frame = operandStack.getOrCreateStackframe(insn); - Operand[] out = frame.getOut(); - Operand opr; - Type returnType; - if (out == null) { - String clsName = AsmUtil.toQualifiedName(insn.owner); - if (clsName.charAt(0) == '[') { - clsName = "java.lang.Object"; - } - JavaClassType cls = identifierFactory.getClassType(AsmUtil.toQualifiedName(clsName)); - List sigTypes = AsmUtil.toJimpleSignatureDesc(insn.desc); - returnType = sigTypes.remove((sigTypes.size() - 1)); - MethodSignature methodSignature = - identifierFactory.getMethodSignature(cls, insn.name, returnType, sigTypes); - int nrArgs = sigTypes.size(); - final Operand[] operands; - AbstractInvokeExpr invoke; - if (isInstance) { - final List args; - if (nrArgs == 0) { - operands = new Operand[1]; - args = Collections.emptyList(); - } else { - Immediate[] argList = new Immediate[nrArgs]; - operands = new Operand[nrArgs + 1]; - - while (nrArgs-- > 0) { - operands[nrArgs] = operandStack.popImmediate(sigTypes.get(nrArgs)); - argList[nrArgs] = (Immediate) operands[nrArgs].stackOrValue(); - } - args = Arrays.asList(argList); - } - - final Operand baseOperand = operandStack.popLocal(); - operands[operands.length - 1] = baseOperand; - Local base = (Local) baseOperand.stackOrValue(); - - switch (op) { - case INVOKESPECIAL: - invoke = Jimple.newSpecialInvokeExpr(base, methodSignature, args); - break; - case INVOKEVIRTUAL: - invoke = Jimple.newVirtualInvokeExpr(base, methodSignature, args); - break; - case INVOKEINTERFACE: - invoke = Jimple.newInterfaceInvokeExpr(base, methodSignature, args); - break; - default: - throw new UnsupportedOperationException("Unknown invoke op:" + op); - } - baseOperand.addUsageInExpr(invoke); - - } else { - if (nrArgs == 0) { - operands = null; - invoke = Jimple.newStaticInvokeExpr(methodSignature, Collections.emptyList()); - - } else { - - operands = new Operand[nrArgs]; - Immediate[] argList = new Immediate[nrArgs]; - - do { - nrArgs--; - operands[nrArgs] = operandStack.popImmediate(sigTypes.get(nrArgs)); - argList[nrArgs] = (Immediate) operands[nrArgs].stackOrValue(); - } while (nrArgs > 0); - - invoke = Jimple.newStaticInvokeExpr(methodSignature, Arrays.asList(argList)); - } - } - - if (operands != null) { - for (int i = 0; i < sigTypes.size(); i++) { - operands[i].addUsageInExpr(invoke); - } - frame.setIn(operands); - } - opr = new Operand(insn, invoke, this); - frame.setOut(opr); + OperandMerging merging = operandStack.getOrCreateMerging(insn); + String clsName = AsmUtil.toQualifiedName(insn.owner); + if (clsName.charAt(0) == '[') { + clsName = "java.lang.Object"; + } + JavaClassType cls = identifierFactory.getClassType(AsmUtil.toQualifiedName(clsName)); + List sigTypes = AsmUtil.toJimpleSignatureDesc(insn.desc); + Type returnType = sigTypes.remove((sigTypes.size() - 1)); + MethodSignature methodSignature = + identifierFactory.getMethodSignature(cls, insn.name, returnType, sigTypes); + int nrArgs = sigTypes.size(); + final Operand[] operands; + Immediate[] argList = new Immediate[nrArgs]; + final List args; + if (!isInstance) { + operands = nrArgs == 0 ? null : new Operand[nrArgs]; } else { - opr = out[0]; - AbstractInvokeExpr expr = (AbstractInvokeExpr) opr.value; - List types = expr.getMethodSignature().getParameterTypes(); - Operand[] oprs; - int nrArgs = types.size(); - assert (isInstance); // TODO: check equivalent to isInstance? - boolean isInstanceMethod = expr instanceof AbstractInstanceInvokeExpr; - if (isInstanceMethod) { - oprs = new Operand[nrArgs + 1]; - while (nrArgs-- != 0) { - oprs[nrArgs] = operandStack.pop(types.get(nrArgs)); - } - oprs[oprs.length - 1] = operandStack.pop(); - frame.mergeIn(currentLineNumber, oprs); - } else { - if (nrArgs > 0) { - oprs = new Operand[nrArgs]; - do { - nrArgs--; - oprs[nrArgs] = operandStack.pop(types.get(nrArgs)); - } while (nrArgs > 0); - - frame.mergeIn(currentLineNumber, oprs); - } + operands = new Operand[nrArgs + 1]; + } + while (nrArgs-- != 0) { + operands[nrArgs] = operandStack.pop(sigTypes.get(nrArgs)); + } + if (isInstance) { + operands[operands.length - 1] = operandStack.pop(); + } + if (operands != null) { + merging.mergeInputs(operands); + } + nrArgs = sigTypes.size(); + while (nrArgs-- != 0) { + argList[nrArgs] = operands[nrArgs].toImmediate(); + } + args = Arrays.asList(argList); + AbstractInvokeExpr invoke; + if (!isInstance) { + invoke = Jimple.newStaticInvokeExpr(methodSignature, args); + } else { + Operand baseOperand = operands[operands.length - 1]; + Local base = baseOperand.toLocal(); + + switch (op) { + case INVOKESPECIAL: + invoke = Jimple.newSpecialInvokeExpr(base, methodSignature, args); + break; + case INVOKEVIRTUAL: + invoke = Jimple.newVirtualInvokeExpr(base, methodSignature, args); + break; + case INVOKEINTERFACE: + invoke = Jimple.newInterfaceInvokeExpr(base, methodSignature, args); + break; + default: + throw new UnsupportedOperationException("Unknown invoke op:" + op); } - returnType = expr.getMethodSignature().getType(); } + Operand opr = new Operand(insn, invoke, this); + merging.mergeOutput(opr); if (AsmUtil.isDWord(returnType)) { operandStack.pushDual(opr); } else if (returnType != VoidType.getInstance()) { operandStack.push(opr); - } else if (!insnToStmt.containsKey(insn)) { + } else { JInvokeStmt stmt = Jimple.newInvokeStmt((AbstractInvokeExpr) opr.value, getStmtPositionInfo()); setStmt(insn, stmt); - opr.addUsageInStmt(stmt); } /* * assign all read ops in case the method modifies any of the fields @@ -1306,79 +1061,58 @@ private void convertMethodInsn(@Nonnull MethodInsnNode insn) { } private void convertInvokeDynamicInsn(@Nonnull InvokeDynamicInsnNode insn) { - StackFrame frame = operandStack.getOrCreateStackframe(insn); - Operand[] out = frame.getOut(); - Operand opr; - Type returnType; - if (out == null) { - // convert info on bootstrap method - MethodSignature bsmMethodRef = toMethodSignature(insn.bsm); - List bsmMethodArgs = new ArrayList<>(insn.bsmArgs.length); - for (Object bsmArg : insn.bsmArgs) { - bsmMethodArgs.add(toSootValue(bsmArg)); - } + OperandMerging merging = operandStack.getOrCreateMerging(insn); + // convert info on bootstrap method + MethodSignature bsmMethodRef = toMethodSignature(insn.bsm); + List bsmMethodArgs = new ArrayList<>(insn.bsmArgs.length); + for (Object bsmArg : insn.bsmArgs) { + bsmMethodArgs.add(toSootValue(bsmArg)); + } - // create ref to actual method - JavaClassType bclass = - identifierFactory.getClassType(JDynamicInvokeExpr.INVOKEDYNAMIC_DUMMY_CLASS_NAME); + // create ref to actual method + JavaClassType bclass = + identifierFactory.getClassType(JDynamicInvokeExpr.INVOKEDYNAMIC_DUMMY_CLASS_NAME); - // Generate parameters & returnType & parameterTypes - List types = AsmUtil.toJimpleSignatureDesc(insn.desc); - int nrArgs = types.size() - 1; - Type[] parameterTypes = new Type[nrArgs]; - Immediate[] methodArgs = new Immediate[nrArgs]; + // Generate parameters & returnType & parameterTypes + List types = AsmUtil.toJimpleSignatureDesc(insn.desc); + int nrArgs = types.size() - 1; + Type[] parameterTypes = new Type[nrArgs]; + Immediate[] methodArgs = new Immediate[nrArgs]; - Operand[] args = new Operand[nrArgs]; - // Beware: Call stack is FIFO, Jimple is linear + Operand[] args = new Operand[nrArgs]; + // Beware: Call stack is FIFO, Jimple is linear - for (int i = nrArgs - 1; i >= 0; i--) { - parameterTypes[i] = types.get(i); - args[i] = operandStack.popImmediate(types.get(i)); - methodArgs[i] = (Immediate) args[i].stackOrValue(); - } - returnType = types.get(types.size() - 1); - - // we always model invokeDynamic method refs as static method references - // of methods on the type SootClass.INVOKEDYNAMIC_DUMMY_CLASS_NAME - MethodSignature methodSig = - identifierFactory.getMethodSignature( - bclass, insn.name, returnType, Arrays.asList(parameterTypes)); - - JDynamicInvokeExpr indy = - Jimple.newDynamicInvokeExpr( - bsmMethodRef, bsmMethodArgs, methodSig, insn.bsm.getTag(), Arrays.asList(methodArgs)); - for (int i = 0; i < types.size() - 1; i++) { - args[i].addUsageInExpr(indy); - } + for (int i = nrArgs - 1; i >= 0; i--) { + parameterTypes[i] = types.get(i); - frame.setIn(args); - opr = new Operand(insn, indy, this); - frame.setOut(opr); - } else { - opr = out[0]; - AbstractInvokeExpr expr = (AbstractInvokeExpr) opr.value; - List types = expr.getMethodSignature().getParameterTypes(); - Operand[] oprs; - int nrArgs = types.size(); - oprs = (nrArgs == 0) ? null : new Operand[nrArgs]; - if (oprs != null) { - while (nrArgs > 0) { - nrArgs--; - oprs[nrArgs] = operandStack.pop(types.get(nrArgs)); - } - frame.mergeIn(currentLineNumber, oprs); - } - returnType = expr.getType(); + args[i] = operandStack.pop(types.get(i)); + } + merging.mergeInputs(args); + for (int i = nrArgs - 1; i >= 0; i--) { + methodArgs[i] = args[i].toImmediate(); } + Type returnType = types.get(types.size() - 1); + + // we always model invokeDynamic method refs as static method references + // of methods on the type SootClass.INVOKEDYNAMIC_DUMMY_CLASS_NAME + MethodSignature methodSig = + identifierFactory.getMethodSignature( + bclass, insn.name, returnType, Arrays.asList(parameterTypes)); + + JDynamicInvokeExpr indy = + Jimple.newDynamicInvokeExpr( + bsmMethodRef, bsmMethodArgs, methodSig, insn.bsm.getTag(), Arrays.asList(methodArgs)); + + Operand opr = new Operand(insn, indy, this); + merging.mergeOutput(opr); if (AsmUtil.isDWord(returnType)) { operandStack.pushDual(opr); } else if (!(returnType instanceof VoidType)) { operandStack.push(opr); - } else if (!insnToStmt.containsKey(insn)) { + } else { JInvokeStmt stmt = Jimple.newInvokeStmt((AbstractInvokeExpr) opr.value, getStmtPositionInfo()); setStmt(insn, stmt); - opr.addUsageInStmt(stmt); } /* * assign all read ops in case the method modifies any of the fields @@ -1387,124 +1121,85 @@ private void convertInvokeDynamicInsn(@Nonnull InvokeDynamicInsnNode insn) { } private void convertMultiANewArrayInsn(@Nonnull MultiANewArrayInsnNode insn) { - StackFrame frame = operandStack.getOrCreateStackframe(insn); - Operand[] out = frame.getOut(); - Operand opr; - if (out == null) { - ArrayType t = (ArrayType) AsmUtil.toJimpleType(insn.desc); - int dims = insn.dims; - Operand[] sizes = new Operand[dims]; - Immediate[] sizeVals = new Immediate[dims]; - while (dims-- != 0) { - sizes[dims] = operandStack.popImmediate(); - sizeVals[dims] = (Immediate) sizes[dims].stackOrValue(); - } - JNewMultiArrayExpr nm = Jimple.newNewMultiArrayExpr(t, Arrays.asList(sizeVals)); - for (int i = 0; i < dims; i++) { - sizes[i].addUsageInExpr(nm); - } - frame.setIn(sizes); - opr = new Operand(insn, nm, this); - frame.setOut(opr); - } else { - opr = out[0]; - int dims = insn.dims; - Operand[] sizes = new Operand[dims]; - while (dims-- != 0) { - sizes[dims] = operandStack.pop(); - } - frame.mergeIn(currentLineNumber, sizes); - } + OperandMerging merging = operandStack.getOrCreateMerging(insn); + ArrayType t = (ArrayType) AsmUtil.toJimpleType(insn.desc); + int dims = insn.dims; + Operand[] sizes = new Operand[dims]; + Immediate[] sizeVals = new Immediate[dims]; + while (dims-- != 0) { + sizes[dims] = operandStack.pop(); + } + merging.mergeInputs(sizes); + dims = insn.dims; + while (dims-- != 0) { + sizeVals[dims] = sizes[dims].toImmediate(); + } + JNewMultiArrayExpr nm = Jimple.newNewMultiArrayExpr(t, Arrays.asList(sizeVals)); + Operand opr = new Operand(insn, nm, this); + merging.mergeOutput(opr); operandStack.push(opr); } private void convertTableSwitchInsn(@Nonnull TableSwitchInsnNode insn) { - StackFrame frame = operandStack.getOrCreateStackframe(insn); + OperandMerging merging = operandStack.getOrCreateMerging(insn); if (insnToStmt.containsKey(insn)) { - frame.mergeIn(currentLineNumber, operandStack.pop()); + merging.mergeInputs(operandStack.pop()); return; } - Operand key = operandStack.popImmediate(); + Operand key = operandStack.pop(); + merging.mergeInputs(key); JSwitchStmt tableSwitchStmt = - Jimple.newTableSwitchStmt( - (Immediate) key.stackOrValue(), insn.min, insn.max, getStmtPositionInfo()); + Jimple.newTableSwitchStmt(key.toImmediate(), insn.min, insn.max, getStmtPositionInfo()); // uphold insertion order! stmtsThatBranchToLabel.putAll(tableSwitchStmt, insn.labels); stmtsThatBranchToLabel.put(tableSwitchStmt, insn.dflt); - frame.setIn(key); setStmt(insn, tableSwitchStmt); - key.addUsageInStmt(tableSwitchStmt); } private void convertTypeInsn(@Nonnull TypeInsnNode insn) { int op = insn.getOpcode(); - StackFrame frame = operandStack.getOrCreateStackframe(insn); - Operand[] out = frame.getOut(); - Operand opr; - if (out == null) { - Expr val; - if (op == NEW) { - val = Jimple.newNewExpr(AsmUtil.toJimpleClassType(insn.desc)); - } else { - Operand op1 = operandStack.popImmediate(); - Value v1 = op1.stackOrValue(); - switch (op) { - case ANEWARRAY: - { - JNewArrayExpr expr = - JavaJimple.getInstance() - .newNewArrayExpr(AsmUtil.arrayTypetoJimpleType(insn.desc), (Immediate) v1); - val = expr; - op1.addUsageInExpr(expr); - break; - } - case CHECKCAST: - { - JCastExpr expr = - Jimple.newCastExpr((Immediate) v1, AsmUtil.toJimpleClassType(insn.desc)); - val = expr; - op1.addUsageInExpr(expr); - break; - } - case INSTANCEOF: - { - JInstanceOfExpr expr = - Jimple.newInstanceOfExpr((Immediate) v1, AsmUtil.toJimpleClassType(insn.desc)); - val = expr; - op1.addUsageInExpr(expr); - break; - } - default: - throw new UnsupportedOperationException("Unknown type op: " + op); - } - op1.addUsageInExpr(val); - frame.setIn(op1); - } - opr = new Operand(insn, val, this); - frame.setOut(opr); + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Expr val; + if (op == NEW) { + val = Jimple.newNewExpr(AsmUtil.toJimpleClassType(insn.desc)); } else { - opr = out[0]; - if (op != NEW) { - frame.mergeIn(currentLineNumber, operandStack.pop()); + Operand op1 = operandStack.pop(); + merging.mergeInputs(op1); + switch (op) { + case ANEWARRAY: + { + val = + JavaJimple.getInstance() + .newNewArrayExpr(AsmUtil.arrayTypetoJimpleType(insn.desc), op1.toImmediate()); + break; + } + case CHECKCAST: + { + val = Jimple.newCastExpr(op1.toImmediate(), AsmUtil.toJimpleClassType(insn.desc)); + break; + } + case INSTANCEOF: + { + val = Jimple.newInstanceOfExpr(op1.toImmediate(), AsmUtil.toJimpleClassType(insn.desc)); + break; + } + default: + throw new UnsupportedOperationException("Unknown type op: " + op); } } + Operand opr = new Operand(insn, val, this); + merging.mergeOutput(opr); operandStack.push(opr); } private void convertVarLoadInsn(@Nonnull VarInsnNode insn) { int op = insn.getOpcode(); boolean dword = op == LLOAD || op == DLOAD; - StackFrame frame = operandStack.getOrCreateStackframe(insn); - Operand[] out = frame.getOut(); - Operand opr; - if (out == null) { - opr = new Operand(insn, getOrCreateLocal(insn.var), this); - frame.setOut(opr); - } else { - opr = out[0]; - } + OperandMerging merging = operandStack.getOrCreateMerging(insn); + Operand opr = new Operand(insn, getOrCreateLocal(insn.var), this); + merging.mergeOutput(opr); if (dword) { operandStack.pushDual(opr); } else { @@ -1515,18 +1210,26 @@ private void convertVarLoadInsn(@Nonnull VarInsnNode insn) { private void convertVarStoreInsn(@Nonnull VarInsnNode insn) { int op = insn.getOpcode(); boolean dword = op == LSTORE || op == DSTORE; - StackFrame frame = operandStack.getOrCreateStackframe(insn); + OperandMerging merging = operandStack.getOrCreateMerging(insn); Operand opr = dword ? operandStack.popDual() : operandStack.pop(); + merging.mergeInputs(opr); Local local = getOrCreateLocal(insn.var); - if (!insnToStmt.containsKey(insn)) { - AbstractDefinitionStmt as = - Jimple.newAssignStmt(local, opr.stackOrValue(), getStmtPositionInfo()); - frame.setIn(opr); - setStmt(insn, as); - opr.addUsageInStmt(as); + AbstractDefinitionStmt as; + if (opr.stackLocal == null || opr.stackLocal == local) { + // Can skip creating a new stack local for the operand + // and store the value in the local directly. + as = Jimple.newAssignStmt(local, opr.value, getStmtPositionInfo()); + opr.stackLocal = local; + setStmt(opr.insn, as); } else { - frame.mergeIn(currentLineNumber, opr); + as = Jimple.newAssignStmt(local, opr.toImmediate(), getStmtPositionInfo()); + setStmt(insn, as); } + // The `local` has just been assigned a new value, + // but an operand with `value == local` might still be on the stack. + // That operand should use the old value, + // so the following call adds a `$stackLocalX = $local` statement + // to persist the old value when necessary. addReadOperandAssignments(local); } @@ -1538,9 +1241,7 @@ private void convertVarInsn(@Nonnull VarInsnNode insn) { convertVarStoreInsn(insn); } else if (op == RET) { /* we handle it, even though it should be removed */ - if (!insnToStmt.containsKey(insn)) { - setStmt(insn, Jimple.newRetStmt(getOrCreateLocal(insn.var), getStmtPositionInfo())); - } + setStmt(insn, Jimple.newRetStmt(getOrCreateLocal(insn.var), getStmtPositionInfo())); } else { throw new UnsupportedOperationException("Unknown var op: " + op); } @@ -1563,21 +1264,15 @@ private void convertLabel(@Nonnull LabelNode ln) { return; } - StackFrame frame = operandStack.getOrCreateStackframe(ln); - Operand[] out = frame.getOut(); - Operand opr; - if (out == null) { - JCaughtExceptionRef ref = JavaJimple.getInstance().newCaughtExceptionRef(); - Local stack = newStackLocal(); - JIdentityStmt as = Jimple.newIdentityStmt(stack, ref, getStmtPositionInfo()); - opr = new Operand(ln, ref, this); - opr.stackLocal = stack; - frame.setOut(opr); - setStmt(ln, as); - opr.addUsageInStmt(as); - } else { - opr = out[0]; + OperandMerging merging = operandStack.getOrCreateMerging(ln); + JCaughtExceptionRef ref = JavaJimple.getInstance().newCaughtExceptionRef(); + Operand opr = new Operand(ln, ref, this); + merging.mergeOutput(opr); + if (opr.stackLocal == null) { + opr.stackLocal = newStackLocal(); } + JIdentityStmt as = Jimple.newIdentityStmt(opr.stackLocal, ref, getStmtPositionInfo()); + setStmt(ln, as); operandStack.push(opr); } @@ -1606,7 +1301,7 @@ private void addEdges( BranchedInsnInfo edge = edges.get(branchingInsn, tgt); if (edge == null) { // [ms] check why this edge could be already there - edge = new BranchedInsnInfo(tgt, operandStack.getStack()); + edge = new BranchedInsnInfo(tgt, operandStack.getStack(), currentLineNumber); edge.addToPrevStack(stackss); edges.put(branchingInsn, tgt, edge); conversionWorklist.add(edge); @@ -1654,20 +1349,23 @@ private void convert() { Operand opr = new Operand(handlerNode, ref, this); opr.stackLocal = local; - worklist.add(new BranchedInsnInfo(handlerNode, Collections.singletonList(opr))); + worklist.add( + new BranchedInsnInfo(handlerNode, Collections.singletonList(opr), currentLineNumber)); // Save the statements inlineExceptionHandlers.put(handlerNode, as); } else { - worklist.add(new BranchedInsnInfo(handlerNode, new ArrayList<>())); + worklist.add(new BranchedInsnInfo(handlerNode, new ArrayList<>(), currentLineNumber)); } } - worklist.add(new BranchedInsnInfo(instructions.getFirst(), Collections.emptyList())); + worklist.add( + new BranchedInsnInfo(instructions.getFirst(), Collections.emptyList(), currentLineNumber)); Table edges = HashBasedTable.create(1, 1); do { BranchedInsnInfo edge = worklist.pollLast(); AbstractInsnNode insn = edge.getInsn(); + currentLineNumber = edge.getLineNumber(); operandStack.setOperandStack( new ArrayList<>(edge.getOperandStacks().get(edge.getOperandStacks().size() - 1))); do { @@ -2032,6 +1730,10 @@ Stmt getLatestVersionOfStmt(@Nonnull Stmt oldStmt) { } void replaceStmt(@Nonnull Stmt oldStmt, Stmt newStmt) { + if (oldStmt == newStmt) { + return; + } + AbstractInsnNode key = null; // TODO: [ms] bit expensive and called a lot? -> find better solution! @@ -2066,9 +1768,9 @@ void replaceStmt(@Nonnull Stmt oldStmt, Stmt newStmt) { /** * * returns all stmts that use this expr * - * @param expr which is used to filter associated Stmts + * @param value which is used to filter associated Stmts */ - public Stream getStmtsThatUse(@Nonnull Expr expr) { + public Stream getStmtsThatUse(@Nonnull Value value) { Stream currentUses = insnToStmt.values().stream() .flatMap( @@ -2076,11 +1778,11 @@ public Stream getStmtsThatUse(@Nonnull Expr expr) { stmt instanceof StmtContainer ? ((StmtContainer) stmt).getStmts().stream() : Stream.of(stmt)) - .filter(stmt -> stmt.getUses().contains(expr)); + .filter(stmt -> stmt.getUses().contains(value)); Stream oldMappedUses = replacedStmt.entrySet().stream() - .filter(stmt -> stmt.getKey().getUses().contains(expr)) + .filter(stmt -> stmt.getKey().getUses().contains(value)) .map(stmt -> getLatestVersionOfStmt(stmt.getValue())); return Stream.concat(currentUses, oldMappedUses); diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/BranchedInsnInfo.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/BranchedInsnInfo.java index aec943546d4..f12eef7ed0a 100644 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/BranchedInsnInfo.java +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/BranchedInsnInfo.java @@ -33,11 +33,14 @@ class BranchedInsnInfo { @Nonnull private final LinkedList prevStacks; /* current stack at edge */ @Nullable private final List> operandStacks = new ArrayList<>(); + private final int lineNumber; - BranchedInsnInfo(@Nonnull AbstractInsnNode insn, @Nonnull List operands) { + BranchedInsnInfo( + @Nonnull AbstractInsnNode insn, @Nonnull List operands, int lineNumber) { this.insn = insn; this.prevStacks = new LinkedList<>(); this.operandStacks.add(operands); + this.lineNumber = lineNumber; } @Nonnull @@ -62,4 +65,8 @@ public LinkedList getPrevStacks() { public void addToPrevStack(@Nonnull Operand[] stacksOperands) { prevStacks.add(stacksOperands); } + + public int getLineNumber() { + return this.lineNumber; + } } diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/Operand.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/Operand.java index fc960b91903..5f185ce9224 100644 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/Operand.java +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/Operand.java @@ -1,4 +1,5 @@ package sootup.java.bytecode.frontend; + /*- * #%L * Soot - a J*va Optimization Framework @@ -20,14 +21,17 @@ * . * #L% */ -import java.util.ArrayList; -import java.util.List; +import java.util.stream.Collectors; import javax.annotation.Nonnull; import javax.annotation.Nullable; import org.objectweb.asm.tree.AbstractInsnNode; +import sootup.core.jimple.Jimple; +import sootup.core.jimple.basic.Immediate; import sootup.core.jimple.basic.Local; +import sootup.core.jimple.basic.StmtPositionInfo; import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.expr.Expr; +import sootup.core.jimple.common.expr.AbstractInvokeExpr; +import sootup.core.jimple.common.stmt.JAssignStmt; import sootup.core.jimple.common.stmt.Stmt; import sootup.core.jimple.visitor.ReplaceUseStmtVisitor; @@ -41,13 +45,11 @@ class Operand { @SuppressWarnings("ConstantConditions") static final Operand DWORD_DUMMY = new Operand(null, null, null); - @Nonnull protected final AbstractInsnNode insn; + @Nonnull protected AbstractInsnNode insn; @Nonnull protected final Value value; @Nullable protected Local stackLocal; @Nonnull private final AsmMethodSource methodSource; - - @Nonnull private final List usedByStmts = new ArrayList<>(); - @Nonnull private final List usedByExpr = new ArrayList<>(); + @Nonnull private final StmtPositionInfo positionInfo; /** * Constructs a new stack operand. @@ -60,64 +62,80 @@ class Operand { this.insn = insn; this.value = value; this.methodSource = methodSource; + this.positionInfo = methodSource == null ? null : methodSource.getStmtPositionInfo(); } - /** - * Adds a usage of this operand (so whenever it is used in a stmt) - * - * @param stmt the usage - */ - void addUsageInStmt(@Nonnull Stmt stmt) { - usedByStmts.add(stmt); - } + Local getOrAssignValueToStackLocal() { + if (stackLocal == null) { + changeStackLocal(methodSource.newStackLocal()); + } - /** - * Adds a usage of this operand (so whenever it is used in a Expr) - * - * @param expr the usage - */ - void addUsageInExpr(@Nonnull Expr expr) { - usedByExpr.add(expr); + return stackLocal; } - /** Updates all statements and expressions that use this Operand. */ - void updateUsages() { - - for (Expr exprUsage : usedByExpr) { - methodSource - .getStmtsThatUse(exprUsage) - .map(methodSource::getLatestVersionOfStmt) - .filter(stmt -> !usedByStmts.contains(stmt)) - .forEach(usedByStmts::add); + void emitStatement() { + if (this == DWORD_DUMMY) { + return; } - if (value == stackOrValue()) return; + if (value instanceof AbstractInvokeExpr) { + methodSource.setStmt(insn, Jimple.newInvokeStmt((AbstractInvokeExpr) value, positionInfo)); + } else { + // create an assignment that uses the value because it might have side effects + getOrAssignValueToStackLocal(); + } + } - ReplaceUseStmtVisitor replaceStmtVisitor = new ReplaceUseStmtVisitor(value, stackOrValue()); + void changeStackLocal(Local newStackLocal) { + Local oldStackLocal = this.stackLocal; - List stmtsToDelete = new ArrayList<>(); + if (oldStackLocal == newStackLocal) { + // nothing to change + return; + } - for (int i = 0; i < usedByStmts.size(); i++) { - Stmt oldUsage = usedByStmts.get(i); + JAssignStmt assignStmt = methodSource.getStmt(insn); + if (assignStmt == null) { + // emit `$newStackLocal = value` + methodSource.setStmt(insn, Jimple.newAssignStmt(newStackLocal, value, positionInfo)); + } else { + assert assignStmt.getLeftOp() == oldStackLocal || assignStmt.getLeftOp() == newStackLocal; + // replace `$oldStackLocal = value` with `$newStackLocal = value` + methodSource.replaceStmt(assignStmt, assignStmt.withVariable(newStackLocal)); + } - // resolve stmt in method source, it might not exist anymore! - oldUsage = methodSource.getLatestVersionOfStmt(oldUsage); + // Replace all usages of `oldStackLocal` with `newStackLocal` + if (oldStackLocal != null) { + ReplaceUseStmtVisitor replaceStmtVisitor = + new ReplaceUseStmtVisitor(oldStackLocal, newStackLocal); + for (Stmt oldUsage : + methodSource.getStmtsThatUse(oldStackLocal).collect(Collectors.toList())) { + oldUsage.accept(replaceStmtVisitor); + Stmt newUsage = replaceStmtVisitor.getResult(); + + if (newUsage != null && oldUsage != newUsage) { + methodSource.replaceStmt(oldUsage, newUsage); + } + } + } - oldUsage.accept(replaceStmtVisitor); - Stmt newUsage = replaceStmtVisitor.getResult(); + this.stackLocal = newStackLocal; + } - if (oldUsage != newUsage) { - methodSource.replaceStmt(oldUsage, newUsage); - usedByStmts.set(i, newUsage); - } + Local toLocal() { + if (stackLocal == null && value instanceof Local) { + return (Local) value; } - usedByStmts.removeAll(stmtsToDelete); + + return getOrAssignValueToStackLocal(); } - /** @return either the stack local allocated for this operand, or its value. */ - @Nonnull - Value stackOrValue() { - return stackLocal == null ? value : stackLocal; + Immediate toImmediate() { + if (stackLocal == null && value instanceof Immediate) { + return (Immediate) value; + } + + return getOrAssignValueToStackLocal(); } /** @@ -127,11 +145,14 @@ Value stackOrValue() { * @return {@code true} if this operand is equal to another operand, {@code false} otherwise. */ boolean equivTo(@Nonnull Operand other) { - // care for DWORD comparison, as stackOrValue is null, which would result in a + Value stackOrValue = stackLocal == null ? value : stackLocal; + Value stackOrValueOther = other.stackLocal == null ? other.value : other.stackLocal; + + // care for DWORD comparison, as asValue is null, which would result in a // NullPointerException return (this == other) || ((this == Operand.DWORD_DUMMY) == (other == Operand.DWORD_DUMMY) - && stackOrValue().equivTo(other.stackOrValue())); + && stackOrValue.equivTo(stackOrValueOther)); } @Override @@ -144,16 +165,6 @@ public AbstractInsnNode getInsn() { return insn; } - @Nonnull - public Value getValue() { - return value; - } - - @Nullable - public Local getStackLocal() { - return stackLocal; - } - @Override public boolean equals(Object other) { return other instanceof Operand && equivTo((Operand) other); diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/OperandMerging.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/OperandMerging.java new file mode 100644 index 00000000000..1fe7d43446c --- /dev/null +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/OperandMerging.java @@ -0,0 +1,159 @@ +package sootup.java.bytecode.frontend; +/*- + * #%L + * Soot - a J*va Optimization Framework + * %% + * Copyright (C) 1997-2020 Raja Vallée-Rai, Andreas Dann, Markus Schmidt and others + * %% + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 2.1 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Lesser Public License for more details. + * + * You should have received a copy of the GNU General Lesser Public + * License along with this program. If not, see + * . + * #L% + */ +import java.util.ArrayList; +import javax.annotation.Nonnull; +import javax.annotation.Nullable; +import sootup.core.jimple.basic.Local; + +/** + * This class tracks the inputs and outputs for an instruction. + * + *

When an instruction is reached from different branches, the state of the operand stack might + * be different. In that case, the different operands from the different branches need to be merged. + * This class does that merging. + * + * @author Aaloan Miftah + */ +final class OperandMerging { + /** + * Keep track of the result of the instruction. The output might get a stack local assigned when + * it is used as a local or immediate. When another branch produces the output and calls + * `mergeOutput`, it should be assigned to the same stack local. + * + *

Interestingly, none of the operations that need to have any inputs/outputs tracked produce + * more than a single output, so this doesn't need to be a list. + */ + @Nullable private Operand output; + + @Nonnull final ArrayList inputOperands = new ArrayList<>(1); + @Nonnull private final AsmMethodSource src; + + /** + * Constructs a new operand merging information holder. + * + * @param src source the merging belongs to. + */ + OperandMerging(@Nonnull AsmMethodSource src) { + this.src = src; + } + + /** + * Merges the output operand produced by the instruction. + * + *

The output from a previous branch might have been assigned to a (stack) local in which case + * any newly created outputs for different branches should be assigned to the same stack local. + * + * @param outputOperand the newly produced operand that will get pushed onto the operand stack + */ + void mergeOutput(@Nonnull Operand outputOperand) { + if (output == null) { + output = outputOperand; + } else { + if (output.stackLocal != null) { + assert outputOperand.stackLocal == null; + outputOperand.changeStackLocal(output.stackLocal); + } + } + } + + /** + * Merges the specified operands with the operands that were previously used with this + * instruction. + * + *

This should be called after the operands have been popped of the stack. + * + *

To convert from the stack-based instructions to register-based instructions, all possible + * combinations of branches need to be walked, because the contents of the operand stack might be + * different when coming from different branches. + * + *

Take the following code as an example: + * + *

System.out.println(n == 1 ? a : "two");
+ * + * If the first branch is taken `a` will be on the stack when the `println` gets invoked, if the + * second branch is taken `"two"` will be on the stack when the `println` gets invoked. This + * method will merge the two (or more) diverging operands by creating a local variable that the + * value of both operands will be assigned to in their respective branches. That local will be + * used when invoking the `println` method. + * + * @param oprs the new operands. + * @throws IllegalArgumentException if the number of new operands is not equal to the number of + * old operands. + */ + void mergeInputs(@Nonnull Operand... oprs) { + if (inputOperands.isEmpty()) { + inputOperands.add(oprs); + // There are no other operands to merge with + return; + } + + if (inputOperands.get(0).length != oprs.length) { + throw new IllegalArgumentException("Invalid in operands length!"); + } + + if (oprs.length == 0) { + // No operands to merge + return; + } + + for (int i = 0; i < oprs.length; i++) { + Operand newOp = oprs[i]; + Local stack = null; + + // Search for a stack local that was already allocated for an operand in a different branch + for (int j = 0; j != inputOperands.size(); j++) { + stack = inputOperands.get(j)[i].stackLocal; + if (stack != null) { + break; + } + } + + // The incoming operand may already have a stack local allocated that can be re-used + if (stack == null && newOp.stackLocal != null) { + stack = newOp.stackLocal; + } + + if (stack == null && inputOperands.get(0)[i].value.equivTo(newOp.value)) { + // all branches have the same value, + // and no stack local was allocated yet, + // so no stack local is needed to converge the values + continue; + } + + // Didn't find any pre-allocated stack local from any operand. + // So create a new stack local. + if (stack == null) { + stack = src.newStackLocal(); + } + + /* add assign statement for prevOp */ + for (int j = 0; j != inputOperands.size(); j++) { + Operand prevOp = inputOperands.get(j)[i]; + prevOp.changeStackLocal(stack); + } + newOp.changeStackLocal(stack); + } + + inputOperands.add(oprs); + } +} diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/OperandStack.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/OperandStack.java index 5e799a3e42a..99cc68bd41d 100644 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/OperandStack.java +++ b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/OperandStack.java @@ -27,10 +27,6 @@ import java.util.Map; import javax.annotation.Nonnull; import org.objectweb.asm.tree.AbstractInsnNode; -import sootup.core.jimple.Jimple; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.constant.Constant; import sootup.core.types.Type; /** @@ -41,21 +37,21 @@ public class OperandStack { @Nonnull private final AsmMethodSource methodSource; private List stack; - @Nonnull public Map frames; + @Nonnull public Map mergings; public OperandStack(@Nonnull AsmMethodSource methodSource, int nrInsn) { this.methodSource = methodSource; - frames = new LinkedHashMap<>(nrInsn); + mergings = new LinkedHashMap<>(nrInsn); } @Nonnull - public StackFrame getOrCreateStackframe(@Nonnull AbstractInsnNode insn) { - StackFrame frame = frames.get(insn); - if (frame == null) { - frame = new StackFrame(methodSource); - frames.put(insn, frame); + public OperandMerging getOrCreateMerging(@Nonnull AbstractInsnNode insn) { + OperandMerging merging = this.mergings.get(insn); + if (merging == null) { + merging = new OperandMerging(methodSource); + this.mergings.put(insn, merging); } - return frame; + return merging; } public void push(@Nonnull Operand opr) { @@ -106,77 +102,15 @@ public Operand pop(@Nonnull Type t) { return AsmUtil.isDWord(t) ? popDual() : pop(); } - @Nonnull - public Operand popLocal(@Nonnull Operand o) { - Value v = o.value; - Local l = o.stackLocal; - if (l == null && !(v instanceof Local)) { - l = o.stackLocal = methodSource.newStackLocal(); - methodSource.setStmt(o.insn, Jimple.newAssignStmt(l, v, methodSource.getStmtPositionInfo())); - o.updateUsages(); - } - return o; - } - - @Nonnull - public Operand popImmediate(@Nonnull Operand o) { - Value v = o.value; - Local l = o.stackLocal; - if (l == null && !(v instanceof Local) && !(v instanceof Constant)) { - l = o.stackLocal = methodSource.newStackLocal(); - methodSource.setStmt(o.insn, Jimple.newAssignStmt(l, v, methodSource.getStmtPositionInfo())); - o.updateUsages(); - } - return o; - } - - @Nonnull - public Operand popStackConst(@Nonnull Operand o) { - Value v = o.value; - Local l = o.stackLocal; - if (l == null && !(v instanceof Constant)) { - l = o.stackLocal = methodSource.newStackLocal(); - methodSource.setStmt(o.insn, Jimple.newAssignStmt(l, v, methodSource.getStmtPositionInfo())); - o.updateUsages(); - } - return o; - } - - @Nonnull - public Operand popLocal() { - return popLocal(pop()); - } - - @SuppressWarnings("unused") - @Nonnull - public Operand popLocalDual() { - return popLocal(popDual()); - } - - @Nonnull - public Operand popImmediate() { - return popImmediate(pop()); - } - - @Nonnull - public Operand popImmediateDual() { - return popImmediate(popDual()); - } - - @Nonnull - public Operand popImmediate(@Nonnull Type t) { - return AsmUtil.isDWord(t) ? popImmediateDual() : popImmediate(); - } - @Nonnull public Operand popStackConst() { - return popStackConst(pop()); + return pop(); } @SuppressWarnings("unused") @Nonnull public Operand popStackConstDual() { - return popStackConst(popDual()); + return popDual(); } @Nonnull diff --git a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/StackFrame.java b/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/StackFrame.java deleted file mode 100644 index 4474eef5a7e..00000000000 --- a/sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/StackFrame.java +++ /dev/null @@ -1,198 +0,0 @@ -package sootup.java.bytecode.frontend; -/*- - * #%L - * Soot - a J*va Optimization Framework - * %% - * Copyright (C) 1997-2020 Raja Vallée-Rai, Andreas Dann, Markus Schmidt and others - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as - * published by the Free Software Foundation, either version 2.1 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Lesser Public License for more details. - * - * You should have received a copy of the GNU General Lesser Public - * License along with this program. If not, see - * . - * #L% - */ -import java.util.ArrayList; -import javax.annotation.Nonnull; -import javax.annotation.Nullable; -import sootup.core.jimple.Jimple; -import sootup.core.jimple.basic.Local; -import sootup.core.jimple.basic.SimpleStmtPositionInfo; -import sootup.core.jimple.basic.StmtPositionInfo; -import sootup.core.jimple.basic.Value; -import sootup.core.jimple.common.stmt.AbstractDefinitionStmt; -import sootup.core.jimple.common.stmt.JAssignStmt; -import sootup.core.jimple.common.stmt.JNopStmt; -import sootup.core.jimple.common.stmt.Stmt; - -/** - * Frame of stack for an instruction. (see ... ) - * - * @author Aaloan Miftah - */ -final class StackFrame { - - @Nullable private Operand[] out; - @Nullable private Local[] inStackLocals; - @Nonnull private final ArrayList in = new ArrayList<>(1); - @Nonnull private final AsmMethodSource src; - - /** - * Constructs a new stack frame. - * - * @param src source the frame belongs to. - */ - StackFrame(@Nonnull AsmMethodSource src) { - this.src = src; - } - - /** @return operands produced by this frame. */ - @Nullable - Operand[] getOut() { - return out; - } - - /** - * Sets the operands used by this frame. - * - * @param oprs the operands. - */ - void setIn(@Nonnull Operand... oprs) { - in.clear(); - in.add(oprs); - inStackLocals = new Local[oprs.length]; - } - - /** - * Sets the operands produced by this frame. - * - * @param oprs the operands. - */ - void setOut(@Nonnull Operand... oprs) { - out = oprs; - } - - /** - * Merges the specified operands with the operands used by this frame. - * - * @param oprs the new operands. - * @throws IllegalArgumentException if the number of new operands is not equal to the number of - * old operands. - */ - void mergeIn(int lineNumber, @Nonnull Operand... oprs) { - if (in.get(0).length != oprs.length) { - throw new IllegalArgumentException("Invalid in operands length!"); - } - - StmtPositionInfo positionInfo; - if (lineNumber > 0) { - positionInfo = new SimpleStmtPositionInfo(lineNumber); - } else { - positionInfo = StmtPositionInfo.createNoStmtPositionInfo(); - } - - final int nrIn = in.size(); - for (int i = 0; i < oprs.length; i++) { - Operand newOp = oprs[i]; - - /* merge, since prevOp != newOp */ - Local stack = inStackLocals[i]; - if (stack != null) { - if (newOp.stackLocal == null) { - newOp.stackLocal = stack; - JAssignStmt as = Jimple.newAssignStmt(stack, newOp.value, positionInfo); - src.setStmt(newOp.insn, as); - newOp.updateUsages(); - } else { - final Value rvalue = newOp.stackOrValue(); - // check for self/identity assignments and ignore them - if (stack != rvalue) { - JAssignStmt as = Jimple.newAssignStmt(stack, rvalue, positionInfo); - src.mergeStmts(newOp.insn, as); - } - } - } else { - for (int j = 0; j != nrIn; j++) { - stack = in.get(j)[i].stackLocal; - if (stack != null) { - break; - } - } - if (stack == null) { - stack = newOp.stackLocal; - if (stack == null) { - stack = src.newStackLocal(); - } - } - /* add assign statement for prevOp */ - for (int j = 0; j != nrIn; j++) { - Operand prevOp = in.get(j)[i]; - if (prevOp.stackLocal == stack) { - continue; - } - if (prevOp.stackLocal == null) { - prevOp.stackLocal = stack; - JAssignStmt as = Jimple.newAssignStmt(stack, prevOp.value, positionInfo); - src.setStmt(prevOp.insn, as); - } else { - Stmt u = src.getStmt(prevOp.insn); - AbstractDefinitionStmt as = - (AbstractDefinitionStmt) - (u instanceof StmtContainer ? ((StmtContainer) u).getFirstStmt() : u); - Value lvb = as.getLeftOp(); - assert lvb == prevOp.stackLocal : "Invalid stack local!"; - prevOp.stackLocal = stack; - } - prevOp.updateUsages(); - } - if (newOp.stackLocal != stack) { - if (newOp.stackLocal == null) { - newOp.stackLocal = stack; - JAssignStmt as = Jimple.newAssignStmt(stack, newOp.value, positionInfo); - src.setStmt(newOp.insn, as); - } else { - Stmt u = src.getStmt(newOp.insn); - if (!(u instanceof JNopStmt)) { - AbstractDefinitionStmt as = - (AbstractDefinitionStmt) - (u instanceof StmtContainer ? ((StmtContainer) u).getFirstStmt() : u); - Value lvb = as.getLeftOp(); - assert lvb == newOp.stackLocal : "Invalid stack local!"; - } - newOp.stackLocal = stack; - } - newOp.updateUsages(); - } - inStackLocals[i] = stack; - } - - /* - * this version uses allocated locals if it finds both operands have stack locals allocated already - */ - /* - * if (stack == null) { if (in.size() != 1) throw new AssertionError("Local h " + in.size()); stack = - * src.newStackLocal(); inStackLocals[i] = stack; ValueBox box = boxes == null ? null : boxes[i]; /* add assign - * statement for prevOp * for (int j = 0; j != nrIn; j++) { Operand prevOp = in.get(j)[i]; prevOp.removeBox(box); if - * (prevOp.stack == null) { prevOp.stack = stack; as = Jimple.v().newAssignStmt(stack, prevOp.value); - * src.setUnit(prevOp.insn, as); prevOp.updateBoxes(); } else { as = Jimple.v().newAssignStmt(stack, - * prevOp.stackOrValue()); src.mergeUnits(prevOp.insn, as); } prevOp.addBox(as.getRightOpBox()); } if (box != null) - * box.setValue(stack); } if (newOp.stack == null) { newOp.stack = stack; as = Jimple.v().newAssignStmt(stack, - * newOp.value); src.setUnit(newOp.insn, as); newOp.updateBoxes(); } else { as = Jimple.v().newAssignStmt(stack, - * newOp.stackOrValue()); src.mergeUnits(newOp.insn, as); } newOp.addBox(as.getRightOpBox()); - */ - } - // add if there is a difference - if (0 < oprs.length) { - in.add(oprs); - } - } -} diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java10/TypeInferenceTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java10/TypeInferenceTest.java index a826432df6d..60ded75e68b 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java10/TypeInferenceTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java10/TypeInferenceTest.java @@ -57,12 +57,10 @@ public List expectedBodyStmts() { "specialinvoke $stack6.(java.io.Reader)>($l3)", "$l4 = $stack6", "label1:", - "$stack9 = $l4", - "$stack7 = virtualinvoke $stack9.()", - "$l2 = $stack7", - "if $stack7 == null goto label2", - "$stack8 = ", - "virtualinvoke $stack8.($l2)", + "$l2 = virtualinvoke $l4.()", + "if $l2 == null goto label2", + "$stack7 = ", + "virtualinvoke $stack7.($l2)", "goto label1", "label2:", "virtualinvoke $l4.()", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/SwitchExprWithYieldTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/SwitchExprWithYieldTest.java index 3389ac236e4..82994ee2dea 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/SwitchExprWithYieldTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java14/SwitchExprWithYieldTest.java @@ -64,6 +64,13 @@ public MethodSignature getMethodSignature() { * } * }; * + * switch (k) { + * case 1: + * s += "single"; + * default: + * s += "somethingElse"; + * }; + * * System.out.println(s); * } * @@ -80,59 +87,51 @@ public List expectedBodyStmts() { "case 3: goto label02", "default: goto label03", "label01:", - "$stack11 = \"single\"", + "$l2 = \"single\"", "goto label04", "label02:", - "$stack11 = \"double\"", + "$l2 = \"double\"", "goto label04", "label03:", - "$stack11 = \"somethingElse\"", + "$l2 = \"somethingElse\"", "label04:", - "$l2 = $stack11", - "$stack12 = $l1", - "switch($stack12)", + "switch($l1)", "case 1: goto label05", "case 2: goto label06", "case 3: goto label06", "default: goto label07", "label05:", - "$stack9 = \"single\"", + "$l2 = \"single\"", "goto label08", "label06:", - "$stack9 = \"double\"", + "$l2 = \"double\"", "goto label08", "label07:", - "$stack9 = \"somethingElse\"", + "$l2 = \"somethingElse\"", "label08:", - "$l2 = $stack9", - "$stack10 = $l1", - "switch($stack10)", + "switch($l1)", "case 1: goto label09", "case 2: goto label10", "case 3: goto label10", "default: goto label11", "label09:", - "$stack7 = \"no fall through\"", + "$l2 = \"no fall through\"", "goto label12", "label10:", - "$stack7 = \"still no fall through\"", + "$l2 = \"still no fall through\"", "goto label12", "label11:", - "$stack7 = \"we will not fall through\"", + "$l2 = \"we will not fall through\"", "label12:", - "$l2 = $stack7", - "$stack8 = $l1", - "switch($stack8)", + "switch($l1)", "case 1: goto label13", "default: goto label14", "label13:", "$l2 = dynamicinvoke \"makeConcatWithConstants\" ($l2) (\"\\u0001single\")", "label14:", - "$stack4 = $l2", - "$stack5 = dynamicinvoke \"makeConcatWithConstants\" ($l2) (\"\\u0001somethingElse\")", + "$l2 = dynamicinvoke \"makeConcatWithConstants\" ($l2) (\"\\u0001somethingElse\")", "$stack3 = ", - "$stack6 = $l2", - "virtualinvoke $stack3.($stack6)", + "virtualinvoke $stack3.($l2)", "return") .collect(Collectors.toCollection(ArrayList::new)); } diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/AccessArraysTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/AccessArraysTest.java index 90711f384ea..dc23780ac18 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/AccessArraysTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/AccessArraysTest.java @@ -76,9 +76,7 @@ public List expectedBodyStmtsIntArrays() { "$l4 = lengthof $l3", "$l5 = 0", "label1:", - "$stack9 = $l5", - "$stack8 = $l4", - "if $stack9 >= $stack8 goto label2", + "if $l5 >= $l4 goto label2", "$l6 = $l3[$l5]", "$l2 = $l6", "$l5 = $l5 + 1", @@ -114,9 +112,7 @@ public List expectedBodyStmtsByteArrays() { "$l4 = lengthof $l3", "$l5 = 0", "label1:", - "$stack9 = $l5", - "$stack8 = $l4", - "if $stack9 >= $stack8 goto label2", + "if $l5 >= $l4 goto label2", "$l6 = $l3[$l5]", "$l2 = $l6", "$l5 = $l5 + 1", @@ -152,9 +148,7 @@ public List expectedBodyStmtsShortArrays() { "$l4 = lengthof $l3", "$l5 = 0", "label1:", - "$stack9 = $l5", - "$stack8 = $l4", - "if $stack9 >= $stack8 goto label2", + "if $l5 >= $l4 goto label2", "$l6 = $l3[$l5]", "$l2 = $l6", "$l5 = $l5 + 1", @@ -190,9 +184,7 @@ public List expectedBodyStmtsLongArrays() { "$l5 = lengthof $l4", "$l6 = 0", "label1:", - "$stack11 = $l6", - "$stack10 = $l5", - "if $stack11 >= $stack10 goto label2", + "if $l6 >= $l5 goto label2", "$l7 = $l4[$l6]", "$l2 = $l7", "$l6 = $l6 + 1", @@ -229,9 +221,7 @@ public List expectedBodyStmtsFloatArrays() { "$l4 = lengthof $l3", "$l5 = 0", "label1:", - "$stack9 = $l5", - "$stack8 = $l4", - "if $stack9 >= $stack8 goto label2", + "if $l5 >= $l4 goto label2", "$l6 = $l3[$l5]", "$l2 = $l6", "$l5 = $l5 + 1", @@ -267,9 +257,7 @@ public List expectedBodyStmtsDoubleArrays() { "$l5 = lengthof $l4", "$l6 = 0", "label1:", - "$stack11 = $l6", - "$stack10 = $l5", - "if $stack11 >= $stack10 goto label2", + "if $l6 >= $l5 goto label2", "$l7 = $l4[$l6]", "$l2 = $l7", "$l6 = $l6 + 1", @@ -304,9 +292,7 @@ public List expectedBodyStmtsBooleanArrays() { "$l4 = lengthof $l3", "$l5 = 0", "label1:", - "$stack9 = $l5", - "$stack8 = $l4", - "if $stack9 >= $stack8 goto label2", + "if $l5 >= $l4 goto label2", "$l6 = $l3[$l5]", "$l2 = $l6", "$l5 = $l5 + 1", @@ -342,9 +328,7 @@ public List expectedBodyStmtsCharArrays() { "$l4 = lengthof $l3", "$l5 = 0", "label1:", - "$stack9 = $l5", - "$stack8 = $l4", - "if $stack9 >= $stack8 goto label2", + "if $l5 >= $l4 goto label2", "$l6 = $l3[$l5]", "$l2 = $l6", "$l5 = $l5 + 1", @@ -378,9 +362,7 @@ public List expectedBodyStmtsStringArrays() { "$l4 = lengthof $l3", "$l5 = 0", "label1:", - "$stack9 = $l5", - "$stack8 = $l4", - "if $stack9 >= $stack8 goto label2", + "if $l5 >= $l4 goto label2", "$l6 = $l3[$l5]", "$l2 = $l6", "$l5 = $l5 + 1", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/AssertStatementTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/AssertStatementTest.java index 283726bc4ec..df0b9f96639 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/AssertStatementTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/AssertStatementTest.java @@ -70,12 +70,11 @@ public List expectedBodyStmtsExtend() { "$stack2 = ", "if $stack2 != 0 goto label1", "if \"\" != null goto label1", - "$stack4 = new java.lang.AssertionError", - "specialinvoke $stack4.()>()", - "throw $stack4", + "$stack3 = new java.lang.AssertionError", + "specialinvoke $stack3.()>()", + "throw $stack3", "label1:", - "$stack3 = 4", - "$l1 = $stack3", + "$l1 = 4", "return") .collect(Collectors.toList()); } @@ -98,21 +97,19 @@ public List expectedBodyStmtsExtend2() { "$stack2 = ", "if $stack2 != 0 goto label1", "if \"first\" != null goto label1", - "$stack7 = new java.lang.AssertionError", - "specialinvoke $stack7.()>()", - "throw $stack7", + "$stack5 = new java.lang.AssertionError", + "specialinvoke $stack5.()>()", + "throw $stack5", "label1:", - "$stack6 = 1", - "$l1 = $stack6", + "$l1 = 1", "$stack3 = ", "if $stack3 != 0 goto label2", "if \"second\" != null goto label2", - "$stack5 = new java.lang.AssertionError", - "specialinvoke $stack5.()>()", - "throw $stack5", + "$stack4 = new java.lang.AssertionError", + "specialinvoke $stack4.()>()", + "throw $stack4", "label2:", - "$stack4 = 2", - "$l1 = $stack4", + "$l1 = 2", "return") .collect(Collectors.toList()); } diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/BooleanOperatorsTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/BooleanOperatorsTest.java index 870446f17bc..9124029e66e 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/BooleanOperatorsTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/BooleanOperatorsTest.java @@ -96,9 +96,7 @@ public List expectedBodyStmtsRelationalOpEqual() { "$l0 := @this: BooleanOperators", "$l1 = 0", "label1:", - "$stack3 = $l1", - "$stack2 = 10", - "if $stack3 > $stack2 goto label2", + "if $l1 > 10 goto label2", "$l1 = $l1 + 1", "if $l1 != 5 goto label1", "goto label2", @@ -129,9 +127,7 @@ public List expectedBodyStmtsRelationalOpNotEqual() { "$l1 = 0", "$l2 = \"\"", "label1:", - "$stack4 = $l1", - "$stack3 = 10", - "if $stack4 >= $stack3 goto label2", + "if $l1 >= 10 goto label2", "$l1 = $l1 + 1", "if $l1 == 5 goto label1", "$l2 = \"i != 5\"", @@ -157,15 +153,13 @@ public List expectedBodyStmtsComplementOp() { return Stream.of( "$l0 := @this: BooleanOperators", "$l1 = 1", - "if $l1 == 0 goto label3", + "if $l1 == 0 goto label2", "if $l1 != 0 goto label1", - "$stack2 = 1", + "$l1 = 1", "goto label2", "label1:", - "$stack2 = 0", + "$l1 = 0", "label2:", - "$l1 = $stack2", - "label3:", "return") .collect(Collectors.toList()); } @@ -211,21 +205,15 @@ public List expectedBodyStmtsLogicalOpAnd() { "if $stack6 == 0 goto label1", "$l5 = \"A\"", "label1:", - "$stack15 = $l3", - "$stack14 = $l4", - "$stack7 = $stack15 & $stack14", + "$stack7 = $l3 & $l4", "if $stack7 == 0 goto label2", "$l5 = \"B\"", "label2:", - "$stack13 = $l1", - "$stack12 = $l3", - "$stack8 = $stack13 & $stack12", + "$stack8 = $l1 & $l3", "if $stack8 == 0 goto label3", "$l5 = \"C\"", "label3:", - "$stack11 = $l4", - "$stack10 = $l2", - "$stack9 = $stack11 & $stack10", + "$stack9 = $l4 & $l2", "if $stack9 == 0 goto label4", "$l5 = \"D\"", "label4:", @@ -274,21 +262,15 @@ public List expectedBodyStmtsLogicalOpOr() { "if $stack6 == 0 goto label1", "$l5 = \"A\"", "label1:", - "$stack15 = $l3", - "$stack14 = $l4", - "$stack7 = $stack15 | $stack14", + "$stack7 = $l3 | $l4", "if $stack7 == 0 goto label2", "$l5 = \"B\"", "label2:", - "$stack13 = $l1", - "$stack12 = $l3", - "$stack8 = $stack13 | $stack12", + "$stack8 = $l1 | $l3", "if $stack8 == 0 goto label3", "$l5 = \"C\"", "label3:", - "$stack11 = $l4", - "$stack10 = $l2", - "$stack9 = $stack11 | $stack10", + "$stack9 = $l4 | $l2", "if $stack9 == 0 goto label4", "$l5 = \"D\"", "label4:", @@ -337,21 +319,15 @@ public List expectedBodyStmtsLogicalOpXor() { "if $stack6 == 0 goto label1", "$l5 = \"A\"", "label1:", - "$stack15 = $l3", - "$stack14 = $l4", - "$stack7 = $stack15 ^ $stack14", + "$stack7 = $l3 ^ $l4", "if $stack7 == 0 goto label2", "$l5 = \"B\"", "label2:", - "$stack13 = $l1", - "$stack12 = $l3", - "$stack8 = $stack13 ^ $stack12", + "$stack8 = $l1 ^ $l3", "if $stack8 == 0 goto label3", "$l5 = \"C\"", "label3:", - "$stack11 = $l4", - "$stack10 = $l2", - "$stack9 = $stack11 ^ $stack10", + "$stack9 = $l4 ^ $l2", "if $stack9 == 0 goto label4", "$l5 = \"D\"", "label4:", @@ -400,18 +376,15 @@ public List expectedBodyStmtsConditionalOpAnd() { "if $l2 == 0 goto label1", "$l5 = \"A\"", "label1:", - "$stack8 = $l3", - "if $stack8 == 0 goto label2", + "if $l3 == 0 goto label2", "if $l4 == 0 goto label2", "$l5 = \"B\"", "label2:", - "$stack7 = $l1", - "if $stack7 == 0 goto label3", + "if $l1 == 0 goto label3", "if $l3 == 0 goto label3", "$l5 = \"C\"", "label3:", - "$stack6 = $l4", - "if $stack6 == 0 goto label4", + "if $l4 == 0 goto label4", "if $l2 == 0 goto label4", "$l5 = \"D\"", "label4:", @@ -459,29 +432,22 @@ public List expectedBodyStmtsConditionalOpOr() { "if $l1 != 0 goto label1", "if $l2 == 0 goto label2", "label1:", - "$stack12 = \"A\"", - "$l5 = $stack12", + "$l5 = \"A\"", "label2:", - "$stack11 = $l3", - "if $stack11 != 0 goto label3", + "if $l3 != 0 goto label3", "if $l4 == 0 goto label4", "label3:", - "$stack10 = \"B\"", - "$l5 = $stack10", + "$l5 = \"B\"", "label4:", - "$stack9 = $l1", - "if $stack9 != 0 goto label5", + "if $l1 != 0 goto label5", "if $l3 == 0 goto label6", "label5:", - "$stack8 = \"C\"", - "$l5 = $stack8", + "$l5 = \"C\"", "label6:", - "$stack7 = $l4", - "if $stack7 != 0 goto label7", + "if $l4 != 0 goto label7", "if $l2 == 0 goto label8", "label7:", - "$stack6 = \"D\"", - "$l5 = $stack6", + "$l5 = \"D\"", "label8:", "return") .collect(Collectors.toList()); @@ -504,12 +470,11 @@ public List expectedBodyStmtsConditionalOp() { "$l1 = 5", "$l2 = \"\"", "if $l1 >= 10 goto label1", - "$stack3 = \"i less than 10\"", + "$l2 = \"i less than 10\"", "goto label2", "label1:", - "$stack3 = \"i greater than 10\"", + "$l2 = \"i greater than 10\"", "label2:", - "$l2 = $stack3", "return") .collect(Collectors.toList()); } diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/BreakInWhileLoopTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/BreakInWhileLoopTest.java index 13f8090bb5b..0b6cefa0d31 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/BreakInWhileLoopTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/BreakInWhileLoopTest.java @@ -41,8 +41,7 @@ public List expectedBodyStmts() { "$l1 = 10", "$l2 = 5", "label1:", - "$stack3 = $l1", - "if $stack3 <= 0 goto label2", + "if $l1 <= 0 goto label2", "$l1 = $l1 + -1", "if $l1 != $l2 goto label1", "goto label2", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ContinueInWhileLoopTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ContinueInWhileLoopTest.java index d7857098ed9..fb8ae4f437b 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ContinueInWhileLoopTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ContinueInWhileLoopTest.java @@ -40,9 +40,7 @@ public List expectedBodyStmts() { "$l0 := @this: ContinueInWhileLoop", "$l1 = 0", "label1:", - "$stack3 = $l1", - "$stack2 = 10", - "if $stack3 >= $stack2 goto label3", + "if $l1 >= 10 goto label3", "if $l1 != 5 goto label2", "$l1 = $l1 + 1", "goto label1", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/DeclareEnumTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/DeclareEnumTest.java index 3808d68147c..a1b42b6366b 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/DeclareEnumTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/DeclareEnumTest.java @@ -50,9 +50,7 @@ public List expectedBodyStmts() { "$l2 = lengthof $l1", "$l3 = 0", "label1:", - "$stack7 = $l3", - "$stack6 = $l2", - "if $stack7 >= $stack6 goto label2", + "if $l3 >= $l2 goto label2", "$l4 = $l1[$l3]", "$stack5 = ", "virtualinvoke $stack5.($l4)", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/DoWhileLoopTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/DoWhileLoopTest.java index 1017b47f52f..20a6a89b107 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/DoWhileLoopTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/DoWhileLoopTest.java @@ -38,9 +38,7 @@ public List expectedBodyStmts() { "$l2 = 0", "label1:", "$l2 = $l2 + 1", - "$stack4 = $l1", - "$stack3 = $l2", - "if $stack4 > $stack3 goto label1", + "if $l1 > $l2 goto label1", "return") .collect(Collectors.toList()); } diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ForEachLoopTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ForEachLoopTest.java index e8ebbfcbc48..703f3f041ab 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ForEachLoopTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ForEachLoopTest.java @@ -51,9 +51,7 @@ public List expectedBodyStmts() { "$l4 = lengthof $l3", "$l5 = 0", "label1:", - "$stack9 = $l5", - "$stack8 = $l4", - "if $stack9 >= $stack8 goto label2", + "if $l5 >= $l4 goto label2", "$l6 = $l3[$l5]", "$l2 = $l2 + 1", "$l5 = $l5 + 1", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ForLoopTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ForLoopTest.java index ea8ceca6ccb..7560b20443b 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ForLoopTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ForLoopTest.java @@ -39,9 +39,7 @@ public List expectedBodyStmts() { "$l2 = 0", "$l3 = 0", "label1:", - "$stack5 = $l3", - "$stack4 = $l1", - "if $stack5 >= $stack4 goto label2", + "if $l3 >= $l1 goto label2", "$l2 = $l2 + 1", "$l3 = $l3 + 1", "goto label1", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/IfElseStatementTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/IfElseStatementTest.java index 96bcd00bf53..2f4ec88f70e 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/IfElseStatementTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/IfElseStatementTest.java @@ -83,8 +83,7 @@ public List expectedBodyStmtsIfStatement() { "if $l1 >= 42 goto label1", "$l2 = 1", "label1:", - "$stack3 = $l2", - "return $stack3") + "return $l2") .collect(Collectors.toList()); } @@ -114,8 +113,7 @@ public List expectedBodyStmtsIfElseStatement() { "label1:", "$l2 = 2", "label2:", - "$stack3 = $l2", - "return $stack3") + "return $l2") .collect(Collectors.toList()); } @@ -151,8 +149,7 @@ public List expectedBodyStmtsIfElseIfStatement() { "label2:", "$l2 = 3", "label3:", - "$stack3 = $l2", - "return $stack3") + "return $l2") .collect(Collectors.toList()); } @@ -190,8 +187,7 @@ public List expectedBodyStmtsIfElseCascadingStatement() { "label2:", "$l2 = 3", "label3:", - "$stack3 = $l2", - "return $stack3") + "return $l2") .collect(Collectors.toList()); } @@ -229,8 +225,7 @@ public List expectedBodyStmtsIfElseCascadingInElseStatement() { "label2:", "$l2 = 22", "label3:", - "$stack3 = $l2", - "return $stack3") + "return $l2") .collect(Collectors.toList()); } @@ -274,8 +269,7 @@ public List expectedBodyStmtsIfElseCascadingElseIfStatement() { "label3:", "$l2 = 2", "label4:", - "$stack3 = $l2", - "return $stack3") + "return $l2") .collect(Collectors.toList()); } @@ -319,8 +313,7 @@ public List expectedBodyStmtsIfElseCascadingElseIfInElseStatement() { "label3:", "$l2 = 23", "label4:", - "$stack3 = $l2", - "return $stack3") + "return $l2") .collect(Collectors.toList()); } } diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/Initialize3DimensionalArraysTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/Initialize3DimensionalArraysTest.java index 7d25ab2b337..de7ae0dbdae 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/Initialize3DimensionalArraysTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/Initialize3DimensionalArraysTest.java @@ -63,30 +63,30 @@ public MethodSignature getMethodSignature(String methodName) { public List expectedBodyStmtsIntArrays() { return Stream.of( "$l0 := @this: Initialize3DimensionalArrays", - "$stack2 = newarray (int[][])[2]", + "$stack5 = newarray (int[][])[2]", "$stack3 = newarray (int[])[2]", - "$stack4 = newarray (int)[3]", - "$stack4[0] = 1", - "$stack4[1] = 2", - "$stack4[2] = 3", - "$stack3[0] = $stack4", - "$stack5 = newarray (int)[2]", - "$stack5[0] = 5", - "$stack5[1] = 6", - "$stack3[1] = $stack5", - "$stack2[0] = $stack3", - "$stack6 = newarray (int[])[2]", - "$stack7 = newarray (int)[3]", - "$stack7[0] = 7", - "$stack7[1] = 8", - "$stack7[2] = 9", - "$stack6[0] = $stack7", + "$stack2 = newarray (int)[3]", + "$stack2[0] = 1", + "$stack2[1] = 2", + "$stack2[2] = 3", + "$stack3[0] = $stack2", + "$stack4 = newarray (int)[2]", + "$stack4[0] = 5", + "$stack4[1] = 6", + "$stack3[1] = $stack4", + "$stack5[0] = $stack3", + "$stack7 = newarray (int[])[2]", + "$stack6 = newarray (int)[3]", + "$stack6[0] = 7", + "$stack6[1] = 8", + "$stack6[2] = 9", + "$stack7[0] = $stack6", "$stack8 = newarray (int)[2]", "$stack8[0] = 10", "$stack8[1] = 11", - "$stack6[1] = $stack8", - "$stack2[1] = $stack6", - "$l1 = $stack2", + "$stack7[1] = $stack8", + "$stack5[1] = $stack7", + "$l1 = $stack5", "return") .collect(Collectors.toList()); } @@ -104,30 +104,30 @@ public List expectedBodyStmtsIntArrays() { public List expectedBodyStmtsByteArrays() { return Stream.of( "$l0 := @this: Initialize3DimensionalArrays", - "$stack2 = newarray (byte[][])[2]", + "$stack5 = newarray (byte[][])[2]", "$stack3 = newarray (byte[])[2]", - "$stack4 = newarray (byte)[3]", - "$stack4[0] = 7", - "$stack4[1] = 8", - "$stack4[2] = 9", - "$stack3[0] = $stack4", - "$stack5 = newarray (byte)[2]", - "$stack5[0] = 10", - "$stack5[1] = 11", - "$stack3[1] = $stack5", - "$stack2[0] = $stack3", - "$stack6 = newarray (byte[])[2]", - "$stack7 = newarray (byte)[3]", - "$stack7[0] = 1", - "$stack7[1] = 2", - "$stack7[2] = 3", - "$stack6[0] = $stack7", + "$stack2 = newarray (byte)[3]", + "$stack2[0] = 7", + "$stack2[1] = 8", + "$stack2[2] = 9", + "$stack3[0] = $stack2", + "$stack4 = newarray (byte)[2]", + "$stack4[0] = 10", + "$stack4[1] = 11", + "$stack3[1] = $stack4", + "$stack5[0] = $stack3", + "$stack7 = newarray (byte[])[2]", + "$stack6 = newarray (byte)[3]", + "$stack6[0] = 1", + "$stack6[1] = 2", + "$stack6[2] = 3", + "$stack7[0] = $stack6", "$stack8 = newarray (byte)[2]", "$stack8[0] = 5", "$stack8[1] = 6", - "$stack6[1] = $stack8", - "$stack2[1] = $stack6", - "$l1 = $stack2", + "$stack7[1] = $stack8", + "$stack5[1] = $stack7", + "$l1 = $stack5", "return") .collect(Collectors.toList()); } @@ -145,28 +145,28 @@ public List expectedBodyStmtsByteArrays() { public List expectedBodyStmtsShortArrays() { return Stream.of( "$l0 := @this: Initialize3DimensionalArrays", - "$stack2 = newarray (short[][])[2]", + "$stack5 = newarray (short[][])[2]", "$stack3 = newarray (short[])[2]", + "$stack2 = newarray (short)[2]", + "$stack2[0] = 10", + "$stack2[1] = 20", + "$stack3[0] = $stack2", "$stack4 = newarray (short)[2]", - "$stack4[0] = 10", - "$stack4[1] = 20", - "$stack3[0] = $stack4", - "$stack5 = newarray (short)[2]", - "$stack5[0] = 40", - "$stack5[1] = 85", - "$stack3[1] = $stack5", - "$stack2[0] = $stack3", - "$stack6 = newarray (short[])[2]", - "$stack7 = newarray (short)[2]", - "$stack7[0] = 56", - "$stack7[1] = 59", - "$stack6[0] = $stack7", + "$stack4[0] = 40", + "$stack4[1] = 85", + "$stack3[1] = $stack4", + "$stack5[0] = $stack3", + "$stack7 = newarray (short[])[2]", + "$stack6 = newarray (short)[2]", + "$stack6[0] = 56", + "$stack6[1] = 59", + "$stack7[0] = $stack6", "$stack8 = newarray (short)[2]", "$stack8[0] = 95", "$stack8[1] = 35", - "$stack6[1] = $stack8", - "$stack2[1] = $stack6", - "$l1 = $stack2", + "$stack7[1] = $stack8", + "$stack5[1] = $stack7", + "$l1 = $stack5", "return") .collect(Collectors.toList()); } @@ -184,29 +184,29 @@ public List expectedBodyStmtsShortArrays() { public List expectedBodyStmtsLongArrays() { return Stream.of( "$l0 := @this: Initialize3DimensionalArrays", - "$stack2 = newarray (long[][])[2]", + "$stack5 = newarray (long[][])[2]", "$stack3 = newarray (long[])[2]", - "$stack4 = newarray (long)[2]", - "$stack4[0] = 547087L", - "$stack4[1] = 654786L", - "$stack3[0] = $stack4", - "$stack5 = newarray (long)[3]", - "$stack5[0] = 547287L", - "$stack5[1] = 864645L", - "$stack5[2] = 6533786L", - "$stack3[1] = $stack5", - "$stack2[0] = $stack3", - "$stack6 = newarray (long[])[2]", - "$stack7 = newarray (long)[2]", - "$stack7[0] = 34565L", - "$stack7[1] = 234L", - "$stack6[0] = $stack7", + "$stack2 = newarray (long)[2]", + "$stack2[0] = 547087L", + "$stack2[1] = 654786L", + "$stack3[0] = $stack2", + "$stack4 = newarray (long)[3]", + "$stack4[0] = 547287L", + "$stack4[1] = 864645L", + "$stack4[2] = 6533786L", + "$stack3[1] = $stack4", + "$stack5[0] = $stack3", + "$stack7 = newarray (long[])[2]", + "$stack6 = newarray (long)[2]", + "$stack6[0] = 34565L", + "$stack6[1] = 234L", + "$stack7[0] = $stack6", "$stack8 = newarray (long)[2]", "$stack8[0] = 9851L", "$stack8[1] = 63543L", - "$stack6[1] = $stack8", - "$stack2[1] = $stack6", - "$l1 = $stack2", + "$stack7[1] = $stack8", + "$stack5[1] = $stack7", + "$l1 = $stack5", "return") .collect(Collectors.toList()); } @@ -224,28 +224,28 @@ public List expectedBodyStmtsLongArrays() { public List expectedBodyStmtsFloatArrays() { return Stream.of( "$l0 := @this: Initialize3DimensionalArrays", - "$stack2 = newarray (float[][])[2]", + "$stack5 = newarray (float[][])[2]", "$stack3 = newarray (float[])[2]", + "$stack2 = newarray (float)[2]", + "$stack2[0] = 3.14F", + "$stack2[1] = 5.46F", + "$stack3[0] = $stack2", "$stack4 = newarray (float)[2]", - "$stack4[0] = 3.14F", - "$stack4[1] = 5.46F", - "$stack3[0] = $stack4", - "$stack5 = newarray (float)[2]", - "$stack5[0] = 2.987F", - "$stack5[1] = 4.87F", - "$stack3[1] = $stack5", - "$stack2[0] = $stack3", - "$stack6 = newarray (float[])[2]", - "$stack7 = newarray (float)[2]", - "$stack7[0] = 65.15F", - "$stack7[1] = 854.18F", - "$stack6[0] = $stack7", + "$stack4[0] = 2.987F", + "$stack4[1] = 4.87F", + "$stack3[1] = $stack4", + "$stack5[0] = $stack3", + "$stack7 = newarray (float[])[2]", + "$stack6 = newarray (float)[2]", + "$stack6[0] = 65.15F", + "$stack6[1] = 854.18F", + "$stack7[0] = $stack6", "$stack8 = newarray (float)[2]", "$stack8[0] = 16.51F", "$stack8[1] = 58.14F", - "$stack6[1] = $stack8", - "$stack2[1] = $stack6", - "$l1 = $stack2", + "$stack7[1] = $stack8", + "$stack5[1] = $stack7", + "$l1 = $stack5", "return") .collect(Collectors.toList()); } @@ -263,27 +263,27 @@ public List expectedBodyStmtsFloatArrays() { public List expectedBodyStmtsDoubleArrays() { return Stream.of( "$l0 := @this: Initialize3DimensionalArrays", - "$stack2 = newarray (double[][])[2]", + "$stack5 = newarray (double[][])[2]", "$stack3 = newarray (double[])[2]", - "$stack4 = newarray (double)[2]", - "$stack4[0] = 6.765414", - "$stack4[1] = 9.676565646", - "$stack3[0] = $stack4", - "$stack5 = newarray (double)[1]", - "$stack5[0] = 45.345435", - "$stack3[1] = $stack5", - "$stack2[0] = $stack3", - "$stack6 = newarray (double[])[2]", - "$stack7 = newarray (double)[2]", - "$stack7[0] = 3.5656", - "$stack7[1] = 68.234234", - "$stack6[0] = $stack7", + "$stack2 = newarray (double)[2]", + "$stack2[0] = 6.765414", + "$stack2[1] = 9.676565646", + "$stack3[0] = $stack2", + "$stack4 = newarray (double)[1]", + "$stack4[0] = 45.345435", + "$stack3[1] = $stack4", + "$stack5[0] = $stack3", + "$stack7 = newarray (double[])[2]", + "$stack6 = newarray (double)[2]", + "$stack6[0] = 3.5656", + "$stack6[1] = 68.234234", + "$stack7[0] = $stack6", "$stack8 = newarray (double)[2]", "$stack8[0] = 68416.651", "$stack8[1] = 65416.5", - "$stack6[1] = $stack8", - "$stack2[1] = $stack6", - "$l1 = $stack2", + "$stack7[1] = $stack8", + "$stack5[1] = $stack7", + "$l1 = $stack5", "return") .collect(Collectors.toList()); } @@ -301,26 +301,26 @@ public List expectedBodyStmtsDoubleArrays() { public List expectedBodyStmtsBooleanArrays() { return Stream.of( "$l0 := @this: Initialize3DimensionalArrays", - "$stack2 = newarray (boolean[][])[2]", + "$stack5 = newarray (boolean[][])[2]", "$stack3 = newarray (boolean[])[2]", - "$stack4 = newarray (boolean)[2]", + "$stack2 = newarray (boolean)[2]", + "$stack2[0] = 1", + "$stack2[1] = 0", + "$stack3[0] = $stack2", + "$stack4 = newarray (boolean)[1]", "$stack4[0] = 1", - "$stack4[1] = 0", - "$stack3[0] = $stack4", - "$stack5 = newarray (boolean)[1]", - "$stack5[0] = 1", - "$stack3[1] = $stack5", - "$stack2[0] = $stack3", - "$stack6 = newarray (boolean[])[2]", - "$stack7 = newarray (boolean)[2]", - "$stack7[0] = 0", - "$stack7[1] = 0", - "$stack6[0] = $stack7", + "$stack3[1] = $stack4", + "$stack5[0] = $stack3", + "$stack7 = newarray (boolean[])[2]", + "$stack6 = newarray (boolean)[2]", + "$stack6[0] = 0", + "$stack6[1] = 0", + "$stack7[0] = $stack6", "$stack8 = newarray (boolean)[1]", "$stack8[0] = 1", - "$stack6[1] = $stack8", - "$stack2[1] = $stack6", - "$l1 = $stack2", + "$stack7[1] = $stack8", + "$stack5[1] = $stack7", + "$l1 = $stack5", "return") .collect(Collectors.toList()); } @@ -338,29 +338,29 @@ public List expectedBodyStmtsBooleanArrays() { public List expectedBodyStmtsCharArrays() { return Stream.of( "$l0 := @this: Initialize3DimensionalArrays", - "$stack2 = newarray (char[][])[2]", + "$stack5 = newarray (char[][])[2]", "$stack3 = newarray (char[])[2]", - "$stack4 = newarray (char)[3]", - "$stack4[0] = 65", - "$stack4[1] = 98", - "$stack4[2] = 38", - "$stack3[0] = $stack4", - "$stack5 = newarray (char)[2]", - "$stack5[0] = 99", - "$stack5[1] = 36", - "$stack3[1] = $stack5", - "$stack2[0] = $stack3", - "$stack6 = newarray (char[])[2]", - "$stack7 = newarray (char)[2]", - "$stack7[0] = 50", - "$stack7[1] = 71", - "$stack6[0] = $stack7", + "$stack2 = newarray (char)[3]", + "$stack2[0] = 65", + "$stack2[1] = 98", + "$stack2[2] = 38", + "$stack3[0] = $stack2", + "$stack4 = newarray (char)[2]", + "$stack4[0] = 99", + "$stack4[1] = 36", + "$stack3[1] = $stack4", + "$stack5[0] = $stack3", + "$stack7 = newarray (char[])[2]", + "$stack6 = newarray (char)[2]", + "$stack6[0] = 50", + "$stack6[1] = 71", + "$stack7[0] = $stack6", "$stack8 = newarray (char)[2]", "$stack8[0] = 97", "$stack8[1] = 37", - "$stack6[1] = $stack8", - "$stack2[1] = $stack6", - "$l1 = $stack2", + "$stack7[1] = $stack8", + "$stack5[1] = $stack7", + "$l1 = $stack5", "return") .collect(Collectors.toList()); } @@ -377,27 +377,27 @@ public List expectedBodyStmtsCharArrays() { public List expectedBodyStmtsStringArrays() { return Stream.of( "$l0 := @this: Initialize3DimensionalArrays", - "$stack2 = newarray (java.lang.String[][])[2]", + "$stack5 = newarray (java.lang.String[][])[2]", "$stack3 = newarray (java.lang.String[])[2]", - "$stack4 = newarray (java.lang.String)[1]", - "$stack4[0] = \"Hello World\"", - "$stack3[0] = $stack4", - "$stack5 = newarray (java.lang.String)[2]", - "$stack5[0] = \"Greetings\"", - "$stack5[1] = \"Welcome\"", - "$stack3[1] = $stack5", - "$stack2[0] = $stack3", - "$stack6 = newarray (java.lang.String[])[2]", - "$stack7 = newarray (java.lang.String)[2]", - "$stack7[0] = \"Future\"", - "$stack7[1] = \"Soot\"", - "$stack6[0] = $stack7", + "$stack2 = newarray (java.lang.String)[1]", + "$stack2[0] = \"Hello World\"", + "$stack3[0] = $stack2", + "$stack4 = newarray (java.lang.String)[2]", + "$stack4[0] = \"Greetings\"", + "$stack4[1] = \"Welcome\"", + "$stack3[1] = $stack4", + "$stack5[0] = $stack3", + "$stack7 = newarray (java.lang.String[])[2]", + "$stack6 = newarray (java.lang.String)[2]", + "$stack6[0] = \"Future\"", + "$stack6[1] = \"Soot\"", + "$stack7[0] = $stack6", "$stack8 = newarray (java.lang.String)[2]", "$stack8[0] = \"UPB\"", "$stack8[1] = \"HNI\"", - "$stack6[1] = $stack8", - "$stack2[1] = $stack6", - "$l1 = $stack2", + "$stack7[1] = $stack8", + "$stack5[1] = $stack7", + "$l1 = $stack5", "return") .collect(Collectors.toList()); } diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/InitializeMultidimensionalArraysTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/InitializeMultidimensionalArraysTest.java index b194ca63c78..0875236c178 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/InitializeMultidimensionalArraysTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/InitializeMultidimensionalArraysTest.java @@ -32,7 +32,6 @@ public void test() { assertJimpleStmts(method, expectedBodyStmtsLongArrays()); method = loadMethod(getMethodSignature("floatArrays")); - assertJimpleStmts(method, expectedBodyStmtsFloatArrays()); method = loadMethod(getMethodSignature("doubleArrays")); @@ -65,22 +64,22 @@ public MethodSignature getMethodSignature(String methodName) { public List expectedBodyStmtsIntArrays() { return Stream.of( "$l0 := @this: InitializeMultidimensionalArrays", - "$stack2 = newarray (int[])[3]", - "$stack3 = newarray (int)[3]", - "$stack3[0] = 1", - "$stack3[1] = 2", - "$stack3[2] = 3", - "$stack2[0] = $stack3", + "$stack3 = newarray (int[])[3]", + "$stack2 = newarray (int)[3]", + "$stack2[0] = 1", + "$stack2[1] = 2", + "$stack2[2] = 3", + "$stack3[0] = $stack2", "$stack4 = newarray (int)[2]", "$stack4[0] = 5", "$stack4[1] = 6", - "$stack2[1] = $stack4", + "$stack3[1] = $stack4", "$stack5 = newarray (int)[3]", "$stack5[0] = 7", "$stack5[1] = 8", "$stack5[2] = 9", - "$stack2[2] = $stack5", - "$l1 = $stack2", + "$stack3[2] = $stack5", + "$l1 = $stack3", "return") .collect(Collectors.toList()); } @@ -97,15 +96,15 @@ public List expectedBodyStmtsIntArrays() { public List expectedBodyStmtsByteArrays() { return Stream.of( "$l0 := @this: InitializeMultidimensionalArrays", - "$stack2 = newarray (byte[])[2]", - "$stack3 = newarray (byte)[2]", - "$stack3[0] = 4", - "$stack3[1] = 5", - "$stack2[0] = $stack3", + "$stack3 = newarray (byte[])[2]", + "$stack2 = newarray (byte)[2]", + "$stack2[0] = 4", + "$stack2[1] = 5", + "$stack3[0] = $stack2", "$stack4 = newarray (byte)[1]", "$stack4[0] = 2", - "$stack2[1] = $stack4", - "$l1 = $stack2", + "$stack3[1] = $stack4", + "$l1 = $stack3", "return") .collect(Collectors.toList()); } @@ -121,16 +120,16 @@ public List expectedBodyStmtsByteArrays() { public List expectedBodyStmtsShortArrays() { return Stream.of( "$l0 := @this: InitializeMultidimensionalArrays", - "$stack2 = newarray (short[])[2]", - "$stack3 = newarray (short)[3]", - "$stack3[0] = 10", - "$stack3[1] = 20", - "$stack3[2] = 30", - "$stack2[0] = $stack3", + "$stack3 = newarray (short[])[2]", + "$stack2 = newarray (short)[3]", + "$stack2[0] = 10", + "$stack2[1] = 20", + "$stack2[2] = 30", + "$stack3[0] = $stack2", "$stack4 = newarray (short)[1]", "$stack4[0] = 40", - "$stack2[1] = $stack4", - "$l1 = $stack2", + "$stack3[1] = $stack4", + "$l1 = $stack3", "return") .collect(Collectors.toList()); } @@ -146,21 +145,21 @@ public List expectedBodyStmtsShortArrays() { public List expectedBodyStmtsLongArrays() { return Stream.of( "$l0 := @this: InitializeMultidimensionalArrays", - "$stack2 = newarray (long[])[3]", - "$stack3 = newarray (long)[2]", - "$stack3[0] = 547087L", - "$stack3[1] = 654786L", - "$stack2[0] = $stack3", + "$stack3 = newarray (long[])[3]", + "$stack2 = newarray (long)[2]", + "$stack2[0] = 547087L", + "$stack2[1] = 654786L", + "$stack3[0] = $stack2", "$stack4 = newarray (long)[3]", "$stack4[0] = 547287L", "$stack4[1] = 864645L", "$stack4[2] = 6533786L", - "$stack2[1] = $stack4", + "$stack3[1] = $stack4", "$stack5 = newarray (long)[2]", "$stack5[0] = 34565L", "$stack5[1] = 234L", - "$stack2[2] = $stack5", - "$l1 = $stack2", + "$stack3[2] = $stack5", + "$l1 = $stack3", "return") .collect(Collectors.toList()); } @@ -178,16 +177,16 @@ public List expectedBodyStmtsLongArrays() { public List expectedBodyStmtsFloatArrays() { return Stream.of( "$l0 := @this: InitializeMultidimensionalArrays", - "$stack2 = newarray (float[])[2]", - "$stack3 = newarray (float)[2]", - "$stack3[0] = 3.14F", - "$stack3[1] = 5.46F", - "$stack2[0] = $stack3", + "$stack3 = newarray (float[])[2]", + "$stack2 = newarray (float)[2]", + "$stack2[0] = 3.14F", + "$stack2[1] = 5.46F", + "$stack3[0] = $stack2", "$stack4 = newarray (float)[2]", "$stack4[0] = 2.987F", "$stack4[1] = 4.87F", - "$stack2[1] = $stack4", - "$l1 = $stack2", + "$stack3[1] = $stack4", + "$l1 = $stack3", "return") .collect(Collectors.toList()); } @@ -206,19 +205,19 @@ public List expectedBodyStmtsFloatArrays() { public List expectedBodyStmtsDoubleArrays() { return Stream.of( "$l0 := @this: InitializeMultidimensionalArrays", - "$stack2 = newarray (double[])[3]", - "$stack3 = newarray (double)[2]", - "$stack3[0] = 6.765414", - "$stack3[1] = 9.676565646", - "$stack2[0] = $stack3", + "$stack3 = newarray (double[])[3]", + "$stack2 = newarray (double)[2]", + "$stack2[0] = 6.765414", + "$stack2[1] = 9.676565646", + "$stack3[0] = $stack2", "$stack4 = newarray (double)[1]", "$stack4[0] = 45.345435", - "$stack2[1] = $stack4", + "$stack3[1] = $stack4", "$stack5 = newarray (double)[2]", "$stack5[0] = 3.5656", "$stack5[1] = 68.234234", - "$stack2[2] = $stack5", - "$l1 = $stack2", + "$stack3[2] = $stack5", + "$l1 = $stack3", "return") .collect(Collectors.toList()); } @@ -235,15 +234,15 @@ public List expectedBodyStmtsDoubleArrays() { public List expectedBodyStmtsBooleanArrays() { return Stream.of( "$l0 := @this: InitializeMultidimensionalArrays", - "$stack2 = newarray (boolean[])[2]", - "$stack3 = newarray (boolean)[2]", - "$stack3[0] = 1", - "$stack3[1] = 0", - "$stack2[0] = $stack3", + "$stack3 = newarray (boolean[])[2]", + "$stack2 = newarray (boolean)[2]", + "$stack2[0] = 1", + "$stack2[1] = 0", + "$stack3[0] = $stack2", "$stack4 = newarray (boolean)[1]", "$stack4[0] = 1", - "$stack2[1] = $stack4", - "$l1 = $stack2", + "$stack3[1] = $stack4", + "$l1 = $stack3", "return") .collect(Collectors.toList()); } @@ -261,21 +260,21 @@ public List expectedBodyStmtsBooleanArrays() { public List expectedBodyStmtsCharArrays() { return Stream.of( "$l0 := @this: InitializeMultidimensionalArrays", - "$stack2 = newarray (char[])[3]", - "$stack3 = newarray (char)[3]", - "$stack3[0] = 65", - "$stack3[1] = 98", - "$stack3[2] = 38", - "$stack2[0] = $stack3", + "$stack3 = newarray (char[])[3]", + "$stack2 = newarray (char)[3]", + "$stack2[0] = 65", + "$stack2[1] = 98", + "$stack2[2] = 38", + "$stack3[0] = $stack2", "$stack4 = newarray (char)[2]", "$stack4[0] = 99", "$stack4[1] = 36", - "$stack2[1] = $stack4", + "$stack3[1] = $stack4", "$stack5 = newarray (char)[2]", "$stack5[0] = 50", "$stack5[1] = 71", - "$stack2[2] = $stack5", - "$l1 = $stack2", + "$stack3[2] = $stack5", + "$l1 = $stack3", "return") .collect(Collectors.toList()); } @@ -292,15 +291,15 @@ public List expectedBodyStmtsCharArrays() { public List expectedBodyStmtsStringArrays() { return Stream.of( "$l0 := @this: InitializeMultidimensionalArrays", - "$stack2 = newarray (java.lang.String[])[2]", - "$stack3 = newarray (java.lang.String)[1]", - "$stack3[0] = \"Hello World\"", - "$stack2[0] = $stack3", + "$stack3 = newarray (java.lang.String[])[2]", + "$stack2 = newarray (java.lang.String)[1]", + "$stack2[0] = \"Hello World\"", + "$stack3[0] = $stack2", "$stack4 = newarray (java.lang.String)[2]", "$stack4[0] = \"Greetings\"", "$stack4[1] = \"Welcome\"", - "$stack2[1] = $stack4", - "$l1 = $stack2", + "$stack3[1] = $stack4", + "$l1 = $stack3", "return") .collect(Collectors.toList()); } diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/LabelStatementTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/LabelStatementTest.java index 6743f3fa4ff..199e0b6e159 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/LabelStatementTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/LabelStatementTest.java @@ -42,9 +42,7 @@ public List expectedBodyStmts() { "$l1 = 20", "$l2 = 1", "label1:", - "$stack5 = $l2", - "$stack4 = $l1", - "if $stack5 >= $stack4 goto label3", + "if $l2 >= $l1 goto label3", "$stack3 = $l2 % 10", "if $stack3 != 0 goto label2", "goto label3", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/LabelledLoopBreakTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/LabelledLoopBreakTest.java index c121ab06dbb..46e3ff35430 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/LabelledLoopBreakTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/LabelledLoopBreakTest.java @@ -40,14 +40,10 @@ public List expectedBodyStmts() { "$l0 := @this: LabelledLoopBreak", "$l1 = 0", "label1:", - "$stack4 = $l1", - "$stack3 = 5", - "if $stack4 >= $stack3 goto label5", + "if $l1 >= 5 goto label5", "$l2 = 0", "label2:", - "$stack6 = $l2", - "$stack5 = 5", - "if $stack6 >= $stack5 goto label4", + "if $l2 >= 5 goto label4", "if $l1 != 1 goto label3", "goto label5", "label3:", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/LocalMergingTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/LocalMergingTest.java new file mode 100644 index 00000000000..f1459ba58d1 --- /dev/null +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/LocalMergingTest.java @@ -0,0 +1,176 @@ +package sootup.java.bytecode.minimaltestsuite.java6; + +import categories.Java8Test; +import java.util.Collections; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import sootup.core.model.SootMethod; +import sootup.java.bytecode.minimaltestsuite.MinimalBytecodeTestSuiteBase; + +@Category(Java8Test.class) +public class LocalMergingTest extends MinimalBytecodeTestSuiteBase { + @Test + public void test() { + SootMethod methodConstant = + loadMethod( + identifierFactory.getMethodSignature( + getDeclaredClassSignature(), + "localMergingWithConstant", + "void", + Collections.singletonList("int"))); + assertJimpleStmts(methodConstant, expectedBodyStmtsConstant()); + + SootMethod methodOtherLocal = + loadMethod( + identifierFactory.getMethodSignature( + getDeclaredClassSignature(), + "localMergingWithOtherLocal", + "void", + Collections.singletonList("int"))); + assertJimpleStmts(methodOtherLocal, expectedBodyStmtsOtherLocal()); + + SootMethod methodDuplicateValue = + loadMethod( + identifierFactory.getMethodSignature( + getDeclaredClassSignature(), + "localMergingWithDuplicateValue", + "void", + Collections.singletonList("int"))); + assertJimpleStmts(methodDuplicateValue, expectedBodyStmtsDuplicateValue()); + + SootMethod methodWithInlining = + loadMethod( + identifierFactory.getMethodSignature( + getDeclaredClassSignature(), + "localMergingWithInlining", + "void", + Collections.singletonList("int"))); + assertJimpleStmts(methodWithInlining, expectedBodyStmtsWithInlining()); + } + + /** + * + * + *
+   * public void localMergingWithConstant(int n) {
+   *     String a = "one";
+   *     // The branch returns either a local or a constant.
+   *     // Because of the divergence neither `a` nor `"two"` should be inlined,
+   *     // but a stack local variable should be created for holding the result of the branch.
+   *     System.out.println(n == 1 ? a : "two");
+   * }
+   * 
+ */ + public List expectedBodyStmtsConstant() { + return Stream.of( + "$l0 := @this: LocalMerging", + "$l1 := @parameter0: int", + "$l2 = \"one\"", + "$stack3 = ", + "if $l1 != 1 goto label1", + "$stack4 = $l2", + "goto label2", + "label1:", + "$stack4 = \"two\"", + "label2:", + "virtualinvoke $stack3.($stack4)", + "return") + .collect(Collectors.toList()); + } + + /** + * + * + *
+   * public void localMergingWithOtherLocal(int n) {
+   *     String a = "one";
+   *     String b = "two";
+   *     // The branch returns either a local or a different local.
+   *     // Because of the divergence neither `a` nor `b` should be inlined,
+   *     // but a stack local variable should be created for holding the result of the branch.
+   *     System.out.println(n == 1 ? a : b);
+   * }
+   * 
+ */ + public List expectedBodyStmtsOtherLocal() { + return Stream.of( + "$l0 := @this: LocalMerging", + "$l1 := @parameter0: int", + "$l2 = \"one\"", + "$l3 = \"two\"", + "$stack4 = ", + "if $l1 != 1 goto label1", + "$stack5 = $l2", + "goto label2", + "label1:", + "$stack5 = $l3", + "label2:", + "virtualinvoke $stack4.($stack5)", + "return") + .collect(Collectors.toList()); + } + + /** + * + * + *
+   * public void localMergingWithDuplicateValue(int n) {
+   *     String a = "one";
+   *     // One of the branches for the first argument contains the constant "two"
+   *     // and the second argument also contains the constant "two".
+   *     // This test ensures that when the first argument gets replaced by a stack local,
+   *     // the second argument isn't replaced as well.
+   *     System.setProperty(n == 1 ? a : "two", "two");
+   * }
+   * 
+ */ + public List expectedBodyStmtsDuplicateValue() { + return Stream.of( + "$l0 := @this: LocalMerging", + "$l1 := @parameter0: int", + "$l2 = \"one\"", + "if $l1 != 1 goto label1", + "$stack3 = $l2", + "goto label2", + "label1:", + "$stack3 = \"two\"", + "label2:", + "staticinvoke ($stack3, \"two\")", + "return") + .collect(Collectors.toList()); + } + + /** + * + * + *
+   * public void localMergingWithInlining(int n) {
+   *     String[] arr = new String[] {"a", "b"};
+   *     int a = 1;
+   *     String b = arr[n == 1 ? 0 : a];
+   * }
+   * 
+ */ + public List expectedBodyStmtsWithInlining() { + return Stream.of( + "$l0 := @this: LocalMerging", + "$l1 := @parameter0: int", + "$stack5 = newarray (java.lang.String)[2]", + "$stack5[0] = \"a\"", + "$stack5[1] = \"b\"", + "$l2 = $stack5", + "$l3 = 1", + "if $l1 != 1 goto label1", + "$stack6 = 0", + "goto label2", + "label1:", + "$stack6 = $l3", + "label2:", + "$l4 = $l2[$stack6]", + "return") + .collect(Collectors.toList()); + } +} diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ReferencingThisTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ReferencingThisTest.java index cbfa91c7475..92d0ac01cdd 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ReferencingThisTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/ReferencingThisTest.java @@ -51,11 +51,11 @@ public List expectedBodyStmts() { "$l0 := @this: ReferencingThis", "$stack2 = ", "virtualinvoke $stack2.(\" this keyword as an argument in the constructor call\")", - "$stack3 = new ReferencingThis", - "$stack5 = $l0.", - "$stack4 = $l0.", - "specialinvoke $stack3.(int,int)>($stack5, $stack4)", - "$l1 = $stack3", + "$stack5 = new ReferencingThis", + "$stack4 = $l0.", + "$stack3 = $l0.", + "specialinvoke $stack5.(int,int)>($stack4, $stack3)", + "$l1 = $stack5", "virtualinvoke $l1.()", "return") .collect(Collectors.toCollection(ArrayList::new)); diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/StatementEvalTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/StatementEvalTest.java index b723d5b1d22..42bfd7f83f8 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/StatementEvalTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/StatementEvalTest.java @@ -38,7 +38,7 @@ public List expectedBodyStmts() { "$l1 = 1", "$stack2 = $l1", "$l1 = 3", - "$l1 = $stack2 + 3", + "$l1 = $stack2 + $l1", "return") .collect(Collectors.toList()); } diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/SynchronizedBlockTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/SynchronizedBlockTest.java index a6dcc79ed37..678121f7c21 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/SynchronizedBlockTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/SynchronizedBlockTest.java @@ -41,22 +41,19 @@ public void test() { public List expectedBodyStmts() { return Stream.of( "$l0 := @this: SynchronizedBlock", - "$stack3 = $l0.", - "$l1 = $stack3", - "entermonitor $stack3", + "$l1 = $l0.", + "entermonitor $l1", "label1:", - "$stack5 = ", - "$stack4 = $l0.", - "virtualinvoke $stack5.($stack4)", - "$stack6 = $l1", - "exitmonitor $stack6", + "$stack4 = ", + "$stack3 = $l0.", + "virtualinvoke $stack4.($stack3)", + "exitmonitor $l1", "label2:", "goto label5", "label3:", - "$stack7 := @caughtexception", - "$l2 = $stack7", - "$stack8 = $l1", - "exitmonitor $stack8", + "$stack5 := @caughtexception", + "$l2 = $stack5", + "exitmonitor $l1", "label4:", "throw $l2", "label5:", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/TryCatchFinallyTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/TryCatchFinallyTest.java index 267a068fa17..57364db356c 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/TryCatchFinallyTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/TryCatchFinallyTest.java @@ -394,11 +394,9 @@ public List expectedBodyStmtsTryCatchFinallyNested() { "$stack13 = ", "virtualinvoke $stack13.($l1)", "label8:", - "$stack14 = \"1finally\"", - "$l1 = $stack14", + "$l1 = \"1finally\"", "$stack6 = ", - "$stack15 = $l1", - "virtualinvoke $stack6.($stack15)", + "virtualinvoke $stack6.($l1)", "goto label9", "label9:", "return", @@ -535,11 +533,9 @@ public List expectedBodyStmtsTryCatchFinallyNestedInCatch() { "$stack10 = ", "virtualinvoke $stack10.($l1)", "label09:", - "$stack15 = \"1finally\"", - "$l1 = $stack15", + "$l1 = \"1finally\"", "$stack11 = ", - "$stack16 = $l1", - "virtualinvoke $stack11.($stack16)", + "virtualinvoke $stack11.($l1)", "goto label10", "label10:", "return", @@ -596,34 +592,34 @@ public List expectedBodyStmtsTryCatchFinallyNestedInFinally() { "label04:", "goto label16", "label05:", - "$stack20 := @caughtexception", - "$l2 = $stack20", + "$stack19 := @caughtexception", + "$l2 = $stack19", "$l1 = \"2catch\"", - "$stack21 = ", - "virtualinvoke $stack21.($l1)", + "$stack20 = ", + "virtualinvoke $stack20.($l1)", "goto label16", "label06:", - "$stack16 := @caughtexception", - "$l2 = $stack16", + "$stack15 := @caughtexception", + "$l2 = $stack15", "$l1 = \"1catch\"", - "$stack17 = ", - "virtualinvoke $stack17.($l1)", + "$stack16 = ", + "virtualinvoke $stack16.($l1)", "label07:", "$l1 = \"1finally\"", - "$stack18 = ", - "virtualinvoke $stack18.($l1)", + "$stack17 = ", + "virtualinvoke $stack17.($l1)", "label08:", "$l1 = \"2try\"", - "$stack19 = ", - "virtualinvoke $stack19.($l1)", + "$stack18 = ", + "virtualinvoke $stack18.($l1)", "label09:", "goto label16", "label10:", - "$stack14 := @caughtexception", - "$l2 = $stack14", + "$stack13 := @caughtexception", + "$l2 = $stack13", "$l1 = \"2catch\"", - "$stack15 = ", - "virtualinvoke $stack15.($l1)", + "$stack14 = ", + "virtualinvoke $stack14.($l1)", "goto label16", "label11:", "$stack10 := @caughtexception", @@ -644,8 +640,7 @@ public List expectedBodyStmtsTryCatchFinallyNestedInFinally() { "$stack9 = ", "virtualinvoke $stack9.($l1)", "label15:", - "$stack13 = $l3", - "throw $stack13", + "throw $l3", "label16:", "return", "catch java.lang.Exception from label01 to label02 with label06", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/UnaryOpIntTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/UnaryOpIntTest.java index 018bc87823d..66e0d6ff947 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/UnaryOpIntTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/UnaryOpIntTest.java @@ -41,9 +41,9 @@ public void test() { public List expectedBodyStmts() { return Stream.of( "$l0 := @this: UnaryOpInt", - "$stack3 = $l0.", - "$stack2 = $l0.", - "$l1 = $stack3 + $stack2", + "$stack2 = $l0.", + "$stack3 = $l0.", + "$l1 = $stack2 + $stack3", "return") .collect(Collectors.toCollection(ArrayList::new)); } diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/WhileLoopTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/WhileLoopTest.java index f02f0a7979f..6914d442760 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/WhileLoopTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/WhileLoopTest.java @@ -38,9 +38,7 @@ public List expectedBodyStmts() { "$l1 = 10", "$l2 = 0", "label1:", - "$stack4 = $l1", - "$stack3 = $l2", - "if $stack4 <= $stack3 goto label2", + "if $l1 <= $l2 goto label2", "$l1 = $l1 + -1", "goto label1", "label2:", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java7/MultiTryCatchTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java7/MultiTryCatchTest.java index 87ce538510a..78eec33e664 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java7/MultiTryCatchTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java7/MultiTryCatchTest.java @@ -60,66 +60,63 @@ public MethodSignature getMethodSignature() { public List expectedBodyStmts() { return Stream.of( "$l0 := @this: MultiTryCatch", - "$stack6 = new java.io.BufferedReader", - "$stack7 = new java.io.FileReader", - "specialinvoke $stack7.(java.lang.String)>(\"file.txt\")", - "specialinvoke $stack6.(java.io.Reader)>($stack7)", - "$l1 = $stack6", + "$stack7 = new java.io.BufferedReader", + "$stack6 = new java.io.FileReader", + "specialinvoke $stack6.(java.lang.String)>(\"file.txt\")", + "specialinvoke $stack7.(java.io.Reader)>($stack6)", + "$l1 = $stack7", "label01:", "$l2 = \"\"", "$l3 = 2", "$stack8 = ", "virtualinvoke $stack8.($l3)", "label02:", - "$stack11 = $l1", - "$stack9 = virtualinvoke $stack11.()", - "$l2 = $stack9", - "if $stack9 == null goto label16", - "$stack10 = ", - "virtualinvoke $stack10.($l2)", + "$l2 = virtualinvoke $l1.()", + "if $l2 == null goto label16", + "$stack9 = ", + "virtualinvoke $stack9.($l2)", "goto label02", "label03:", - "$stack18 := @caughtexception", - "$l2 = $stack18", + "$stack15 := @caughtexception", + "$l2 = $stack15", "label04:", "virtualinvoke $l1.()", "label05:", "goto label19", "label06:", - "$stack17 := @caughtexception", - "$l2 = $stack17", + "$stack14 := @caughtexception", + "$l2 = $stack14", "goto label19", "label07:", - "$stack16 := @caughtexception", - "$l2 = $stack16", + "$stack13 := @caughtexception", + "$l2 = $stack13", "label08:", "virtualinvoke $l1.()", "label09:", "goto label19", "label10:", - "$stack15 := @caughtexception", - "$l2 = $stack15", + "$stack12 := @caughtexception", + "$l2 = $stack12", "goto label19", "label11:", - "$stack13 := @caughtexception", - "$l4 = $stack13", + "$stack11 := @caughtexception", + "$l4 = $stack11", "label12:", "virtualinvoke $l1.()", "label13:", "goto label15", "label14:", - "$stack12 := @caughtexception", - "$l5 = $stack12", + "$stack10 := @caughtexception", + "$l5 = $stack10", "label15:", - "$stack14 = $l4", - "throw $stack14", + "throw $l4", "label16:", "virtualinvoke $l1.()", "label17:", "goto label19", "label18:", - "$stack19 := @caughtexception", - "$l2 = $stack19", + "$stack16 := @caughtexception", + "$l2 = $stack16", "goto label19", "label19:", "return", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java7/SwitchCaseStatementWithStringTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java7/SwitchCaseStatementWithStringTest.java index d8dc068d1bf..d3de128c445 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java7/SwitchCaseStatementWithStringTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java7/SwitchCaseStatementWithStringTest.java @@ -68,13 +68,13 @@ public List expectedBodyStmts() { "case 110339486: goto label3", "default: goto label4", "label1:", - "$stack9 = virtualinvoke $l3.(\"one\")", - "if $stack9 == 0 goto label4", + "$stack8 = virtualinvoke $l3.(\"one\")", + "if $stack8 == 0 goto label4", "$l4 = 0", "goto label4", "label2:", - "$stack8 = virtualinvoke $l3.(\"two\")", - "if $stack8 == 0 goto label4", + "$stack7 = virtualinvoke $l3.(\"two\")", + "if $stack7 == 0 goto label4", "$l4 = 1", "goto label4", "label3:", @@ -82,8 +82,7 @@ public List expectedBodyStmts() { "if $stack6 == 0 goto label4", "$l4 = 2", "label4:", - "$stack7 = $l4", - "switch($stack7)", + "switch($l4)", "case 0: goto label5", "case 1: goto label6", "case 2: goto label7", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java7/TryWithResourcesTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java7/TryWithResourcesTest.java index 1c65fcba61b..bcc41246968 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java7/TryWithResourcesTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java7/TryWithResourcesTest.java @@ -47,30 +47,28 @@ public void test() { public List expectedBodyStmts() { return Stream.of( "$l0 := @this: TryWithResources", - "$stack6 = new java.io.BufferedReader", - "$stack7 = new java.io.FileReader", - "specialinvoke $stack7.(java.lang.String)>(\"file.txt\")", - "specialinvoke $stack6.(java.io.Reader)>($stack7)", - "$l1 = $stack6", + "$stack7 = new java.io.BufferedReader", + "$stack6 = new java.io.FileReader", + "specialinvoke $stack6.(java.lang.String)>(\"file.txt\")", + "specialinvoke $stack7.(java.io.Reader)>($stack6)", + "$l1 = $stack7", "$l2 = null", "label01:", "$l3 = \"\"", "label02:", - "$stack10 = $l1", - "$stack8 = virtualinvoke $stack10.()", - "$l3 = $stack8", - "if $stack8 == null goto label11", - "$stack9 = ", - "virtualinvoke $stack9.($l3)", + "$l3 = virtualinvoke $l1.()", + "if $l3 == null goto label11", + "$stack8 = ", + "virtualinvoke $stack8.($l3)", "goto label02", "label03:", - "$stack14 := @caughtexception", - "$l3 = $stack14", + "$stack11 := @caughtexception", + "$l3 = $stack11", "$l2 = $l3", "throw $l3", "label04:", - "$stack12 := @caughtexception", - "$l4 = $stack12", + "$stack10 := @caughtexception", + "$l4 = $stack10", "label05:", "if $l1 == null goto label10", "if $l2 == null goto label09", @@ -79,15 +77,14 @@ public List expectedBodyStmts() { "label07:", "goto label10", "label08:", - "$stack11 := @caughtexception", - "$l5 = $stack11", + "$stack9 := @caughtexception", + "$l5 = $stack9", "virtualinvoke $l2.($l5)", "goto label10", "label09:", "virtualinvoke $l1.()", "label10:", - "$stack13 = $l4", - "throw $stack13", + "throw $l4", "label11:", "if $l1 == null goto label16", "if $l2 == null goto label15", @@ -96,8 +93,8 @@ public List expectedBodyStmts() { "label13:", "goto label16", "label14:", - "$stack15 := @caughtexception", - "$l3 = $stack15", + "$stack12 := @caughtexception", + "$l3 = $stack12", "virtualinvoke $l2.($l3)", "goto label16", "label15:", diff --git a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java9/TryWithResourcesConciseTest.java b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java9/TryWithResourcesConciseTest.java index 6a861a22c78..93fda577191 100644 --- a/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java9/TryWithResourcesConciseTest.java +++ b/sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java9/TryWithResourcesConciseTest.java @@ -68,37 +68,34 @@ public void test() { public List expectedBodyStmts() { return Stream.of( "$l0 := @this: TryWithResourcesConcise", - "$stack5 = new java.io.BufferedReader", - "$stack6 = new java.io.FileReader", - "specialinvoke $stack6.(java.lang.String)>(\"file.txt\")", - "specialinvoke $stack5.(java.io.Reader)>($stack6)", - "$l1 = $stack5", + "$stack6 = new java.io.BufferedReader", + "$stack5 = new java.io.FileReader", + "specialinvoke $stack5.(java.lang.String)>(\"file.txt\")", + "specialinvoke $stack6.(java.io.Reader)>($stack5)", + "$l1 = $stack6", "$l2 = $l1", "label1:", "$l3 = \"\"", "label2:", - "$stack9 = $l1", - "$stack7 = virtualinvoke $stack9.()", - "$l3 = $stack7", - "if $stack7 == null goto label8", - "$stack8 = ", - "virtualinvoke $stack8.($l3)", + "$l3 = virtualinvoke $l1.()", + "if $l3 == null goto label8", + "$stack7 = ", + "virtualinvoke $stack7.($l3)", "goto label2", "label3:", - "$stack11 := @caughtexception", - "$l3 = $stack11", + "$stack9 := @caughtexception", + "$l3 = $stack9", "if $l2 == null goto label7", "label4:", "virtualinvoke $l2.()", "label5:", "goto label7", "label6:", - "$stack10 := @caughtexception", - "$l4 = $stack10", + "$stack8 := @caughtexception", + "$l4 = $stack8", "virtualinvoke $l3.($l4)", "label7:", - "$stack12 = $l3", - "throw $stack12", + "throw $l3", "label8:", "if $l2 == null goto label9", "virtualinvoke $l2.()",