Skip to content

Commit 629420d

Browse files
committed
Empirical evaluation for JLAMP 2022
- Updated README.md - New module for benchmarks (sdg-bench) - Added representations for the original JSysDG and for the Allen&Horwitz SDG (graph and slicing algorithm) - Fixed bugs: * Accept abstract methods (without a body) * Avoid generating constructors for interfaces * Handle calls outside methods * Handle methods inside methods * Locate and handle all method calls (including on the left-hand side of assignments and in return statements). * Correctly determining the type of -output- nodes * Various errors related to object tree location and traversal
1 parent b91f0ef commit 629420d

24 files changed

+606
-63
lines changed

README.md

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Warning: all method calls must resolve to a method declaration. If your Java pro
1313

1414
JavaSDGSlicer manages its dependencies through maven, so you need to have the JDK (≥11) and Maven installed, then run
1515
```
16-
mvn package
16+
mvn package -Dmaven.test.skip
1717
```
1818

1919
A fat jar containing all the project's dependencies can be then located at `./sdg-cli/target/sdg-cli-{version}-jar-with-dependencies.jar`.
@@ -57,7 +57,7 @@ java -jar sdg-cli.jar --help
5757
Our slicer requires the input Java program to be compilable, so all libraries must be provided using the `-i` flag. For the cases where the source code is not available, you may include the required libraries in the Java classpath by using the following call:
5858

5959
```
60-
java -cp sdg-cli.jar:your-libraries.jar es.upv.slicing.cli.Slicer -c Example.java#11:sum
60+
java -cp your-libraries.jar -jar sdg-cli.jar -c Example.java#11:sum
6161
```
6262

6363
This approach produces lower quality slices, as the contents of the library calls are unknown.
@@ -77,6 +77,4 @@ If the graph is of interest, it can be outputted in `dot` or PDF format via `SDG
7777

7878
## Missing Java features
7979

80-
* Object-oriented features: abstract classes, interfaces, class, method and field inheritance, anonymous classes, lambdas.
8180
* Parallel features: threads, shared memory, synchronized methods, etc.
82-
* Exception handling: `finally`, try with resources.

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,6 @@
4040
<module>sdg-core</module>
4141
<module>sdg-cli</module>
4242
<module>javaparser-symbol-solver-core</module>
43+
<module>sdg-bench</module>
4344
</modules>
4445
</project>

sdg-bench/pom.xml

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>sdg</artifactId>
7+
<groupId>es.upv.mist.slicing</groupId>
8+
<version>1.3.0</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
12+
<artifactId>sdg-bench</artifactId>
13+
14+
<properties>
15+
<maven.compiler.source>11</maven.compiler.source>
16+
<maven.compiler.target>11</maven.compiler.target>
17+
</properties>
18+
19+
<dependencies>
20+
<dependency>
21+
<groupId>es.upv.mist.slicing</groupId>
22+
<artifactId>sdg-core</artifactId>
23+
<version>${project.version}</version>
24+
</dependency>
25+
<dependency>
26+
<groupId>com.github.javaparser</groupId>
27+
<artifactId>javaparser-core</artifactId>
28+
<version>3.23.1</version>
29+
</dependency>
30+
</dependencies>
31+
32+
<build>
33+
<plugins>
34+
<plugin>
35+
<groupId>org.apache.maven.plugins</groupId>
36+
<artifactId>maven-assembly-plugin</artifactId>
37+
<version>3.3.0</version>
38+
<configuration>
39+
<archive>
40+
<manifest>
41+
<addClasspath>true</addClasspath>
42+
<mainClass>es.upv.mist.slicing.benchmark.BenchSC</mainClass>
43+
</manifest>
44+
</archive>
45+
<descriptorRefs>
46+
<descriptorRef>jar-with-dependencies</descriptorRef>
47+
</descriptorRefs>
48+
</configuration>
49+
<executions>
50+
<execution>
51+
<id>assemble-all</id>
52+
<phase>package</phase>
53+
<goals>
54+
<goal>single</goal>
55+
</goals>
56+
</execution>
57+
</executions>
58+
</plugin>
59+
</plugins>
60+
</build>
61+
</project>
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
package es.upv.mist.slicing.benchmark;
2+
3+
import com.github.javaparser.ParseException;
4+
import com.github.javaparser.Problem;
5+
import com.github.javaparser.StaticJavaParser;
6+
import com.github.javaparser.ast.CompilationUnit;
7+
import com.github.javaparser.ast.NodeList;
8+
import com.github.javaparser.ast.stmt.ReturnStmt;
9+
import com.github.javaparser.symbolsolver.resolution.typesolvers.JavaParserTypeSolver;
10+
import es.upv.mist.slicing.arcs.pdg.StructuralArc;
11+
import es.upv.mist.slicing.graphs.augmented.ASDG;
12+
import es.upv.mist.slicing.graphs.augmented.PSDG;
13+
import es.upv.mist.slicing.graphs.exceptionsensitive.AllenSDG;
14+
import es.upv.mist.slicing.graphs.exceptionsensitive.ESSDG;
15+
import es.upv.mist.slicing.graphs.jsysdg.JSysDG;
16+
import es.upv.mist.slicing.graphs.jsysdg.OriginalJSysDG;
17+
import es.upv.mist.slicing.graphs.sdg.SDG;
18+
import es.upv.mist.slicing.nodes.GraphNode;
19+
import es.upv.mist.slicing.nodes.SyntheticNode;
20+
import es.upv.mist.slicing.slicing.OriginalJSysDGSlicingAlgorithm;
21+
import es.upv.mist.slicing.slicing.SlicingCriterion;
22+
import es.upv.mist.slicing.utils.NodeHashSet;
23+
import es.upv.mist.slicing.utils.StaticTypeSolver;
24+
25+
import java.io.File;
26+
import java.io.FileNotFoundException;
27+
import java.io.PrintWriter;
28+
import java.util.*;
29+
import java.util.function.Predicate;
30+
import java.util.stream.Collectors;
31+
import java.util.stream.Stream;
32+
33+
public class BenchSC {
34+
protected static final int BUILD_TIMES = 0, SLICE_TIMES = 1, SLICE_SIZES = 2, EXIT = 3;
35+
protected final String[] dirIncludeSet = System.getProperty("sInclude", "").split(":");
36+
protected String graphType;
37+
38+
public void benchmark() {
39+
// Obtain parameters
40+
String baselineGraph = System.getProperty("sGraphBaseline");
41+
String benchGraph = System.getProperty("sGraphBench");
42+
int minIter = Integer.parseInt(System.getProperty("sMinIter", "100"));
43+
String outputPrefix = System.getProperty("sOutputPrefix", "result");
44+
45+
// Files
46+
File buildBaseTime = new File(outputPrefix + "buildBaseTime.out");
47+
File buildBenchTime = new File(outputPrefix + "buildBenchTime.out");
48+
File nodeCount = new File(outputPrefix + "nodesBaseline.out");
49+
File sliceBaseTime = new File(outputPrefix + "sliceBaseTime.out");
50+
File sliceBenchTime = new File(outputPrefix + "sliceBenchTime.out");
51+
52+
// Configure JavaParser
53+
StaticJavaParser.getConfiguration().setAttributeComments(false);
54+
StaticTypeSolver.addTypeSolverJRE();
55+
for (String directory : dirIncludeSet)
56+
StaticTypeSolver.addTypeSolver(new JavaParserTypeSolver(directory));
57+
58+
while (true) {
59+
switch (selectOption()) {
60+
case BUILD_TIMES:
61+
graphType = baselineGraph;
62+
timedRun(this::buildGraph, minIter, buildBaseTime);
63+
graphType = benchGraph;
64+
timedRun(this::buildGraph, minIter, buildBenchTime);
65+
break;
66+
case SLICE_SIZES:
67+
try (PrintWriter pw = new PrintWriter(nodeCount)) {
68+
graphType = "JSysDG";
69+
SDG baseSDG = buildGraph();
70+
pw.println("# File format: for each SDG type, the total number of nodes and then the number of ");
71+
pw.println(baseSDG.vertexSet().size());
72+
Collection<SlicingCriterion> baseCriteria = findSCs(baseSDG);
73+
System.out.printf("There are %d return object SCs", findReturnObjectSCs(baseSDG).size());
74+
System.out.printf("There are %d real nodes SCs", findRealSCs(baseSDG).size());
75+
System.exit(0);
76+
for (SlicingCriterion sc : baseCriteria) {
77+
int baseNodes = new OriginalJSysDGSlicingAlgorithm((JSysDG) baseSDG).traverse(sc.findNode(baseSDG)).getGraphNodes().size();
78+
int benchNodes = baseSDG.slice(sc).getGraphNodes().size();
79+
pw.printf("\"%s\",%d,%d\n", sc, baseNodes, benchNodes);
80+
}
81+
} catch (FileNotFoundException e) {
82+
throw new RuntimeException(e);
83+
}
84+
break;
85+
case SLICE_TIMES:
86+
try {
87+
graphType = baselineGraph;
88+
SDG sdg1 = buildGraph();
89+
try (PrintWriter pw = new PrintWriter(sliceBaseTime)) {
90+
pw.println("# SC id, SC time sequence");
91+
for (SlicingCriterion sc : findSCs(sdg1))
92+
timedRun(() -> sdg1.slice(sc), minIter, pw);
93+
}
94+
graphType = benchGraph;
95+
SDG sdg2 = buildGraph();
96+
try (PrintWriter pw = new PrintWriter(sliceBenchTime)) {
97+
pw.println("# SC id, SC time sequence");
98+
for (SlicingCriterion sc : findSCs(sdg2))
99+
timedRun(() -> sdg2.slice(sc), minIter, pw);
100+
}
101+
} catch (FileNotFoundException e) {
102+
throw new RuntimeException(e);
103+
}
104+
break;
105+
case EXIT:
106+
return;
107+
}
108+
}
109+
}
110+
111+
protected int selectOption() {
112+
Scanner in = new Scanner(System.in);
113+
System.out.println("Select an option:");
114+
System.out.println("\t[0]: Time the building of the graphs");
115+
System.out.println("\t[1]: Time the slicing of the graphs");
116+
System.out.println("\t[2]: Number of nodes per slice");
117+
System.out.println("\t[3]: Exit");
118+
System.out.print("> ");
119+
return in.nextInt();
120+
}
121+
122+
protected SDG buildGraph() {
123+
try {
124+
// Build the SDG
125+
Set<CompilationUnit> units = new NodeHashSet<>();
126+
List<Problem> problems = new LinkedList<>();
127+
for (File file : (Iterable<File>) findAllJavaFiles(dirIncludeSet)::iterator)
128+
parse(file, units, problems);
129+
if (!problems.isEmpty()) {
130+
for (Problem p : problems)
131+
System.out.println(" * " + p.getVerboseMessage());
132+
throw new ParseException("Some problems were found while parsing files or folders");
133+
}
134+
135+
SDG sdg = createGraph(graphType);
136+
sdg.build(new NodeList<>(units));
137+
return sdg;
138+
} catch (ParseException e) {
139+
throw new RuntimeException(e);
140+
}
141+
}
142+
143+
private void parse(File file, Set<CompilationUnit> units, List<Problem> problems) {
144+
try {
145+
units.add(StaticJavaParser.parse(file));
146+
} catch (FileNotFoundException e) {
147+
problems.add(new Problem(e.getLocalizedMessage(), null, e));
148+
}
149+
}
150+
151+
protected Stream<File> findAllJavaFiles(String[] files) {
152+
Stream.Builder<File> builder = Stream.builder();
153+
for (String fileName : files) {
154+
File file = new File(fileName);
155+
if (file.isDirectory())
156+
findAllJavaFiles(file, builder);
157+
else
158+
builder.accept(file);
159+
}
160+
return builder.build();
161+
}
162+
163+
protected void findAllJavaFiles(File directory, Stream.Builder<File> builder) {
164+
File[] files = directory.listFiles();
165+
if (files == null)
166+
return;
167+
for (File f : files) {
168+
if (f.isDirectory())
169+
findAllJavaFiles(f, builder);
170+
else if (f.getName().endsWith(".java"))
171+
builder.accept(f);
172+
}
173+
}
174+
175+
protected SDG createGraph(String graphName) {
176+
switch (graphName) {
177+
case "SDG": return new SDG();
178+
case "ASDG": return new ASDG();
179+
case "PSDG": return new PSDG();
180+
case "ESSDG": return new ESSDG();
181+
case "AllenSDG": return new AllenSDG();
182+
case "JSysDG": return new JSysDG();
183+
case "OriginalJSysDG": return new OriginalJSysDG();
184+
default:
185+
throw new IllegalArgumentException();
186+
}
187+
}
188+
189+
protected long[] timedRun(Runnable runnable, int iterations) {
190+
long[] times = new long[iterations];
191+
long t1, t2;
192+
for (int i = -1; i < iterations; i++) {
193+
t1 = System.nanoTime();
194+
runnable.run();
195+
t2 = System.nanoTime();
196+
if (i >= 0)
197+
times[i] = t2 - t1; // Times stored in nanoseconds
198+
}
199+
return times;
200+
}
201+
202+
protected void timedRun(Runnable runnable, int minIter, File file) {
203+
long[] data = timedRun(runnable, minIter);
204+
try (PrintWriter pw = new PrintWriter(file)) {
205+
for (long d : data)
206+
pw.println(d);
207+
} catch (FileNotFoundException e) {
208+
throw new RuntimeException(e);
209+
}
210+
}
211+
212+
protected void timedRun(Runnable runnable, int minIter, PrintWriter pw) {
213+
long[] data = timedRun(runnable, minIter);
214+
StringBuilder builder = new StringBuilder();
215+
for (int i = 0; i < data.length; i++) {
216+
if (i > 0)
217+
builder.append(',');
218+
builder.append(data[i]);
219+
}
220+
pw.println(builder);
221+
}
222+
223+
protected Collection<SlicingCriterion> findSCs(SDG sdg) {
224+
return findReturnObjectSCs(sdg);
225+
}
226+
227+
protected Collection<SlicingCriterion> findRealSCs(SDG sdg) {
228+
return sdg.vertexSet().stream()
229+
.filter(Predicate.not(SyntheticNode.class::isInstance))
230+
.filter(Predicate.not(GraphNode::isImplicitInstruction))
231+
.sorted()
232+
.map(n -> (SlicingCriterion) graph -> Set.of(n))
233+
.collect(Collectors.toList());
234+
}
235+
236+
protected Collection<SlicingCriterion> findReturnObjectSCs(SDG sdg) {
237+
return sdg.vertexSet().stream()
238+
.filter(gn -> gn.getAstNode() instanceof ReturnStmt)
239+
.flatMap(gn -> sdg.outgoingEdgesOf(gn).stream()
240+
.filter(StructuralArc.class::isInstance)
241+
.map(sdg::getEdgeTarget))
242+
.filter(gn -> sdg.outgoingEdgesOf(gn).stream().anyMatch(StructuralArc.class::isInstance))
243+
.map(n -> new SlicingCriterion() {
244+
public Set<GraphNode<?>> findNode(SDG sdg) { return Set.of(n); }
245+
public String toString() { return n.getLongLabel(); }
246+
})
247+
.collect(Collectors.toList());
248+
}
249+
250+
public static void main(String... args) {
251+
new BenchSC().benchmark();
252+
}
253+
}

sdg-core/src/main/java/es/upv/mist/slicing/graphs/CallGraph.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ protected boolean addEdge(CallableDeclaration<?> source, CallableDeclaration<?>
130130
return addEdge(findVertexByDeclaration(source), findVertexByDeclaration(target), edge);
131131
}
132132

133+
protected boolean addEdge(TypeDeclaration<?> source, CallableDeclaration<?> target, Resolvable<? extends ResolvedMethodLikeDeclaration> call) {
134+
return false; // TODO: handle static blocks
135+
}
136+
133137
/** Find the calls to methods and constructors (edges) in the given list of compilation units. */
134138
protected void buildEdges(NodeList<CompilationUnit> arg) {
135139
arg.accept(new VoidVisitorAdapter<Void>() {
@@ -229,7 +233,12 @@ protected void createPolyEdges(MethodDeclaration decl, MethodCallExpr call) {
229233
}
230234

231235
protected void createNormalEdge(CallableDeclaration<?> decl, Resolvable<? extends ResolvedMethodLikeDeclaration> call) {
232-
addEdge(declStack.peek(), decl, call);
236+
if (declStack.isEmpty() && typeStack.isEmpty())
237+
throw new IllegalStateException("Trying to link call with empty declaration stack! " + decl.getDeclarationAsString() + " : " + call.toString());
238+
if (declStack.isEmpty())
239+
addEdge(typeStack.peek(), decl, call);
240+
else
241+
addEdge(declStack.peek(), decl, call);
233242
}
234243

235244
// Other structures
@@ -251,7 +260,7 @@ protected GraphNode<?> findGraphNode(Resolvable<? extends ResolvedMethodLikeDecl
251260
for (GraphNode<?> node : cfgMap.get(declaration).vertexSet())
252261
if (node.containsCall(n))
253262
return node;
254-
throw new NodeNotFoundException("call " + n + " could not be located!");
263+
throw new NodeNotFoundException("call " + n + " could not be located! cfg was " + cfgMap.get(declaration).rootNode.getLongLabel() + " and declaration was " + declaration.getDeclarationAsString());
255264
}
256265

257266
/** A vertex containing the declaration it represents. It only exists because
@@ -302,6 +311,7 @@ public static class Edge<T extends Resolvable<? extends ResolvedMethodLikeDeclar
302311

303312
public Edge(T call, GraphNode<?> graphNode) {
304313
assert call instanceof MethodCallExpr || call instanceof ObjectCreationExpr || call instanceof ExplicitConstructorInvocationStmt;
314+
assert graphNode.containsCall(call);
305315
this.call = call;
306316
this.graphNode = graphNode;
307317
}

0 commit comments

Comments
 (0)