Skip to content

Commit 055ae49

Browse files
committed
compare traces based on their aliasing structure and symbols
1 parent 2217ee2 commit 055ae49

File tree

5 files changed

+156
-5
lines changed

5 files changed

+156
-5
lines changed

svm-jcore/src/main/java/com/lexicalscope/svm/vm/j/code/AsmSMethodName.java

+27
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,21 @@
33
import static com.lexicalscope.svm.vm.j.JavaConstants.*;
44
import static org.objectweb.asm.Type.*;
55

6+
import java.util.ArrayList;
7+
import java.util.List;
8+
69
import org.objectweb.asm.Type;
710

11+
import com.google.common.primitives.Ints;
812
import com.lexicalscope.svm.vm.j.SVirtualMethodName;
913
import com.lexicalscope.svm.vm.j.klass.SMethodDescriptor;
1014

1115
public final class AsmSMethodName implements Comparable<AsmSMethodName>, SMethodDescriptor {
1216
private final String klassName;
1317
private final SVirtualMethodName virtualName;
1418
private final int hashCode;
19+
private final int[] objectArgIndexes;
20+
private final boolean returnTypeIsObject;
1521

1622
public AsmSMethodName(
1723
final String klassName,
@@ -21,6 +27,23 @@ public AsmSMethodName(
2127
this.klassName = klassName;
2228
this.virtualName = new AsmSVirtualMethodName(name, desc);
2329
this.hashCode = klassName.hashCode() ^ virtualName.hashCode();
30+
this.objectArgIndexes = indexesOfObjectArgs(desc);
31+
this.returnTypeIsObject = getReturnType(desc).getSort() == Type.OBJECT;
32+
}
33+
34+
private static int[] indexesOfObjectArgs(final String desc) {
35+
final List<Integer> result = new ArrayList<>();
36+
final Type[] argumentTypes = Type.getArgumentTypes(desc);
37+
for (int j = 0; j < argumentTypes.length; j++) {
38+
if(argumentTypes[j].getSort() == Type.OBJECT) {
39+
result.add(j);
40+
}
41+
}
42+
return Ints.toArray(result);
43+
}
44+
45+
@Override public boolean returnIsObject() {
46+
return returnTypeIsObject;
2447
}
2548

2649
public AsmSMethodName(
@@ -88,6 +111,10 @@ public int argSize() {
88111
return getArgumentsAndReturnSizes(desc()) >> 2;
89112
}
90113

114+
@Override public int[] objectArgIndexes() {
115+
return objectArgIndexes;
116+
}
117+
91118
@Override
92119
public int returnCount() {
93120
return getArgumentsAndReturnSizes(desc()) & 0x03;

svm-jcore/src/main/java/com/lexicalscope/svm/vm/j/klass/SMethodDescriptor.java

+2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ public interface SMethodDescriptor extends SMethodName {
1212

1313
String desc();
1414

15+
int[] objectArgIndexes();
16+
boolean returnIsObject();
1517
int argSize();
1618
int returnCount();
1719

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package com.lexicalscope.svm.partition.trace.symb;
2+
3+
import static com.lexicalscope.svm.partition.trace.TraceBuilder.trace;
4+
import static com.lexicalscope.svm.partition.trace.symb.SymbolicTraceMatchers.equivalentTo;
5+
import static org.hamcrest.MatcherAssert.assertThat;
6+
import static org.hamcrest.Matchers.not;
7+
8+
import org.junit.Before;
9+
import org.junit.Rule;
10+
import org.junit.Test;
11+
12+
import com.lexicalscope.svm.j.instruction.symbolic.symbols.ISymbol;
13+
import com.lexicalscope.svm.partition.trace.TraceBuilder;
14+
import com.lexicalscope.svm.vm.symb.junit.Fresh;
15+
import com.lexicalscope.svm.vm.symb.junit.SolverRule;
16+
17+
public class TestTraceEquivalenceModuloAliasing {
18+
@Rule public final SolverRule solver = new SolverRule();
19+
public static class Example { }
20+
21+
private @Fresh ISymbol symbol1;
22+
private @Fresh ISymbol symbol2;
23+
24+
private final Object address1 = new Object();
25+
private final Object address2 = new Object();
26+
private final Object address3 = new Object();
27+
28+
private TraceBuilder receiverAliasesParameterV1;
29+
private TraceBuilder receiverAliasesParameterV2;
30+
private TraceBuilder receiverDoesNotAliasParameter;
31+
32+
@Before public void createTraces() {
33+
receiverAliasesParameterV1 = trace()
34+
.methodCall(Example.class, "call", "(Ljava/lang/Object;)V", address1, address1)
35+
.methodReturn(Example.class, "call", "(Ljava/lang/Object;)V");
36+
37+
receiverAliasesParameterV2 = trace()
38+
.methodCall(Example.class, "call", "(Ljava/lang/Object;)V", address2, address2)
39+
.methodReturn(Example.class, "call", "(Ljava/lang/Object;)V");
40+
41+
receiverDoesNotAliasParameter = trace()
42+
.methodCall(Example.class, "call", "(Ljava/lang/Object;)V", address1, address3)
43+
.methodReturn(Example.class, "call", "(Ljava/lang/Object;)V");
44+
}
45+
46+
@Test public void sameAliasingAreEquivalent() throws Exception {
47+
assertThat(receiverAliasesParameterV1, equivalentTo(solver, receiverAliasesParameterV2));
48+
}
49+
50+
@Test public void differentAliasingAreNotEquivalent() throws Exception {
51+
assertThat(receiverAliasesParameterV1, not(equivalentTo(solver, receiverDoesNotAliasParameter)));
52+
assertThat(receiverAliasesParameterV2, not(equivalentTo(solver, receiverDoesNotAliasParameter)));
53+
}
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.lexicalscope.svm.partition.trace;
2+
3+
public class Alias {
4+
private final int index;
5+
6+
public Alias(final int index) {
7+
this.index = index;
8+
}
9+
10+
@Override public boolean equals(final Object obj) {
11+
return obj != null
12+
&& obj.getClass().equals(this.getClass())
13+
&& ((Alias) obj).index == this.index;
14+
}
15+
16+
@Override public int hashCode() {
17+
return index;
18+
}
19+
20+
@Override public String toString() {
21+
return "Alias-" + index;
22+
}
23+
}

svm-partition-trace/src/main/java/com/lexicalscope/svm/partition/trace/Trace.java

+50-5
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,81 @@
11
package com.lexicalscope.svm.partition.trace;
22

33
import static com.lexicalscope.svm.partition.trace.Trace.CallReturn.CALL;
4+
import static java.util.Arrays.copyOf;
45

56
import java.util.Arrays;
7+
import java.util.HashMap;
68
import java.util.Iterator;
79
import java.util.LinkedList;
810
import java.util.List;
11+
import java.util.Map;
912

1013
import com.google.common.base.Joiner;
1114
import com.lexicalscope.svm.stack.trace.SMethodName;
15+
import com.lexicalscope.svm.vm.j.klass.SMethodDescriptor;
1216

1317
public class Trace implements Iterable<Trace> {
1418
private final Trace previous;
15-
private final SMethodName method;
19+
private final SMethodDescriptor method;
1620
private final CallReturn callReturn;
1721
private final Object[] args;
22+
private final Map<Object, Alias> map;
23+
private final int nextAlias;
1824
public enum CallReturn { CALL, RETURN }
1925

2026
public Trace() {
21-
this(null, null, null, new Object[0]);
27+
this(null, new HashMap<Object, Alias>(), 0, null, null, new Object[0]);
2228
}
2329

24-
private Trace(final Trace trace, final SMethodName method, final CallReturn callReturn, final Object[] args) {
30+
private Trace(
31+
final Trace trace,
32+
final Map<Object, Alias> map,
33+
final int nextAlias,
34+
final SMethodDescriptor method,
35+
final CallReturn callReturn,
36+
final Object[] args) {
37+
this.nextAlias = nextAlias;
2538
assert !Arrays.asList(args).contains(null);
2639
this.previous = trace;
40+
this.map = map;
2741
this.method = method;
2842
this.callReturn = callReturn;
2943
this.args = args;
3044
}
3145

32-
public Trace extend(final SMethodName methodCalled, final CallReturn callReturn, final Object ... args) {
33-
return new Trace(this, methodCalled, callReturn, args);
46+
public Trace extend(final SMethodDescriptor methodCalled, final CallReturn callReturn, final Object ... args) {
47+
final Object[] normalisedArgs = copyOf(args, args.length);
48+
int newNextAlias = nextAlias;
49+
Map<Object, Alias> newMap = map;
50+
51+
if(callReturn.equals(CallReturn.CALL)) {
52+
for (final int i : methodCalled.objectArgIndexes()) {
53+
Alias alias;
54+
if(null == (alias = newMap.get(args[i + 1]))) {
55+
// TODO[tim] do COW here
56+
if(map == newMap) {
57+
newMap = new HashMap<>(map);
58+
}
59+
alias = new Alias(newNextAlias++);
60+
newMap.put(args[i + 1], alias);
61+
}
62+
normalisedArgs[i + 1] = alias;
63+
}
64+
}
65+
if(callReturn.equals(CallReturn.CALL) || methodCalled.returnIsObject()) {
66+
Alias alias;
67+
if(null == (alias = newMap.get(args[0]))) {
68+
// TODO[tim] do COW here
69+
if(map == newMap) {
70+
newMap = new HashMap<>(map);
71+
}
72+
alias = new Alias(newNextAlias++);
73+
newMap.put(args[0], alias);
74+
}
75+
normalisedArgs[0] = alias;
76+
}
77+
78+
return new Trace(this, newMap, newNextAlias, methodCalled, callReturn, normalisedArgs);
3479
}
3580

3681
public List<Trace> asList() {

0 commit comments

Comments
 (0)