Skip to content

Commit 949ed25

Browse files
committed
don't replace the operand value when creating a new stack local when merging
Instead, rely on the fact that all `convert` methods override their respective statements. That means just changing the incoming operands will automatically correctly update the statement. Also added a test case to make sure this works with the special case of using a normal local as a stack local.
1 parent d2dc5e5 commit 949ed25

File tree

7 files changed

+50
-43
lines changed

7 files changed

+50
-43
lines changed
193 Bytes
Binary file not shown.

shared-test-resources/miniTestSuite/java6/source/LocalMerging.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,4 +24,10 @@ public void localMergingWithDuplicateValue(int n) {
2424
// the second argument isn't replaced as well.
2525
System.setProperty(n == 1 ? a : "two", "two");
2626
}
27+
28+
public void localMergingWithInlining(int n) {
29+
String[] arr = new String[] {"a", "b"};
30+
int a = 1;
31+
String b = arr[n == 1 ? 0 : a];
32+
}
2733
}

sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/AsmMethodSource.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1215,14 +1215,13 @@ private void convertVarStoreInsn(@Nonnull VarInsnNode insn) {
12151215
merging.mergeInputs(opr);
12161216
Local local = getOrCreateLocal(insn.var);
12171217
AbstractDefinitionStmt as;
1218-
if (opr.stackLocal == null) {
1218+
if (opr.stackLocal == null || opr.stackLocal == local) {
12191219
// Can skip creating a new stack local for the operand
12201220
// and store the value in the local directly.
12211221
as = Jimple.newAssignStmt(local, opr.value, getStmtPositionInfo());
1222-
// TODO check that this works correctly with the merging
12231222
opr.stackLocal = local;
12241223
setStmt(opr.insn, as);
1225-
} else if (opr.stackLocal != local) {
1224+
} else {
12261225
as = Jimple.newAssignStmt(local, opr.toImmediate(), getStmtPositionInfo());
12271226
setStmt(insn, as);
12281227
}

sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/Operand.java

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ class Operand {
4646

4747
@Nonnull protected AbstractInsnNode insn;
4848
@Nonnull protected final Value value;
49-
// TODO probably need to store the `insn` for the STORE instruction when a *real*
50-
// local is used here and use that when merging,
51-
// or more specifically when changing to a different stack local in `changeStackLocal`
5249
@Nullable protected Local stackLocal;
5350
@Nonnull private final AsmMethodSource methodSource;
5451

@@ -78,11 +75,6 @@ void emitStatement() {
7875
return;
7976
}
8077

81-
if (methodSource.getStmt(insn) != null) {
82-
// the operand is already used, which means side effects already happen as well
83-
return;
84-
}
85-
8678
if (value instanceof AbstractInvokeExpr) {
8779
methodSource.setStmt(
8880
insn,

sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/OperandMerging.java

Lines changed: 1 addition & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,7 @@
2323
import java.util.ArrayList;
2424
import javax.annotation.Nonnull;
2525
import javax.annotation.Nullable;
26-
import org.objectweb.asm.tree.AbstractInsnNode;
2726
import sootup.core.jimple.basic.Local;
28-
import sootup.core.jimple.common.stmt.Stmt;
29-
import sootup.core.jimple.visitor.ReplaceUseStmtVisitor;
3027

3128
/**
3229
* This class tracks the inputs and outputs for an instruction.
@@ -38,8 +35,6 @@
3835
* @author Aaloan Miftah
3936
*/
4037
final class OperandMerging {
41-
@Nonnull private final AbstractInsnNode insn;
42-
4338
/**
4439
* Keep track of the result of the instruction. The output might get a stack local assigned when
4540
* it is used as a local or immediate. When another branch produces the output and calls
@@ -58,8 +53,7 @@ final class OperandMerging {
5853
*
5954
* @param src source the merging belongs to.
6055
*/
61-
OperandMerging(@Nonnull AbstractInsnNode insn, @Nonnull AsmMethodSource src) {
62-
this.insn = insn;
56+
OperandMerging(@Nonnull AsmMethodSource src) {
6357
this.src = src;
6458
}
6559

@@ -148,8 +142,6 @@ void mergeInputs(@Nonnull Operand... oprs) {
148142

149143
// Didn't find any pre-allocated stack local from any operand.
150144
// So create a new stack local.
151-
// TODO use a special case when the statement is an assignment to a local since in that case
152-
// we can use the local directly instead of creating a new stack local
153145
if (stack == null) {
154146
stack = src.newStackLocal();
155147
}
@@ -160,28 +152,6 @@ void mergeInputs(@Nonnull Operand... oprs) {
160152
prevOp.changeStackLocal(stack);
161153
}
162154
newOp.changeStackLocal(stack);
163-
164-
// TODO `in.get(0)` is weird because of the index?
165-
// TODO make it more obvious that this is only run the first time
166-
// replace the operand in the statement that *started* the merge
167-
ReplaceUseStmtVisitor replaceUseStmtVisitor =
168-
new ReplaceUseStmtVisitor(inputOperands.get(0)[i].value, stack);
169-
// TODO how to handle the same value being in the the statement multiple times but only one
170-
// time because of the operand? (Something like `System.out.println(operand, "hello")` with
171-
// the operand also having the value "two")
172-
// this might require a callback(?) to change the statement; alternative we could do the
173-
// merging *before* constructing the statement and then replace the statement if it differs
174-
// from an already existing one
175-
// This actually works right now because the `ReplaceUseExprVisitor` only checks object
176-
// equality meaning the
177-
// two instances of the constant are different and only the correct instance is replaced
178-
Stmt oldStatement = this.src.getStmt(this.insn);
179-
// TODO `oldStatement` might not exist when a STORE instruction was used to set the
180-
// stackLocal
181-
if (oldStatement != null) {
182-
oldStatement.accept(replaceUseStmtVisitor);
183-
this.src.replaceStmt(oldStatement, replaceUseStmtVisitor.getResult());
184-
}
185155
}
186156

187157
inputOperands.add(oprs);

sootup.java.bytecode/src/main/java/sootup/java/bytecode/frontend/OperandStack.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ public OperandStack(@Nonnull AsmMethodSource methodSource, int nrInsn) {
4848
public OperandMerging getOrCreateMerging(@Nonnull AbstractInsnNode insn) {
4949
OperandMerging merging = this.mergings.get(insn);
5050
if (merging == null) {
51-
merging = new OperandMerging(insn, methodSource);
51+
merging = new OperandMerging(methodSource);
5252
this.mergings.put(insn, merging);
5353
}
5454
return merging;

sootup.java.bytecode/src/test/java/sootup/java/bytecode/minimaltestsuite/java6/LocalMergingTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,15 @@ public void test() {
4040
"void",
4141
Collections.singletonList("int")));
4242
assertJimpleStmts(methodDuplicateValue, expectedBodyStmtsDuplicateValue());
43+
44+
SootMethod methodWithInlining =
45+
loadMethod(
46+
identifierFactory.getMethodSignature(
47+
getDeclaredClassSignature(),
48+
"localMergingWithInlining",
49+
"void",
50+
Collections.singletonList("int")));
51+
assertJimpleStmts(methodWithInlining, expectedBodyStmtsWithInlining());
4352
}
4453

4554
/**
@@ -133,4 +142,35 @@ public List<String> expectedBodyStmtsDuplicateValue() {
133142
"return")
134143
.collect(Collectors.toList());
135144
}
145+
146+
/**
147+
*
148+
*
149+
* <pre>
150+
* public void localMergingWithInlining(int n) {
151+
* String[] arr = new String[] {"a", "b"};
152+
* int a = 1;
153+
* String b = arr[n == 1 ? 0 : a];
154+
* }
155+
* </pre>
156+
*/
157+
public List<String> expectedBodyStmtsWithInlining() {
158+
return Stream.of(
159+
"$l0 := @this: LocalMerging",
160+
"$l1 := @parameter0: int",
161+
"$stack5 = newarray (java.lang.String)[2]",
162+
"$stack5[0] = \"a\"",
163+
"$stack5[1] = \"b\"",
164+
"$l2 = $stack5",
165+
"$l3 = 1",
166+
"if $l1 != 1 goto label1",
167+
"$stack6 = 0",
168+
"goto label2",
169+
"label1:",
170+
"$stack6 = $l3",
171+
"label2:",
172+
"$l4 = $l2[$stack6]",
173+
"return")
174+
.collect(Collectors.toList());
175+
}
136176
}

0 commit comments

Comments
 (0)