Skip to content

Commit ef9b4c5

Browse files
committed
Merge branch 'entry_points_txt' of https://github.com/ponder-lab/Java-8-Stream-Refactoring into entry_points_txt
2 parents ff53872 + ee306f8 commit ef9b4c5

File tree

20 files changed

+523
-126
lines changed

20 files changed

+523
-126
lines changed

README.md

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ This prototype refactoring plug-in for [Eclipse](http://eclipse.org) represents
1515

1616
Explicit entry points may be marked using the appropriate annotation found in the corresponding [annotation library][annotations].
1717

18-
Explicit entry points can also be marked using importing entry points from a txt file. Each time we run the tool, a txt file named "entry_points.txt" is generated and contained in the current directory of workspace. Then, before next time we run tool to evaluate the same project, move or copy "entry_points.txt" into project directory or workspace directory of the project. While evaluating the project, the tool will ignore the explicit entry points which are added manually and regonize the explicit entry points through the file automatically.
18+
Explicit entry points can also be marked using importing entry points from a txt file. Each time we run the tool, a txt file named "entry_points.txt" is generated and contained in the current directory of workspace. Then, before next time we run tool to evaluate the same project, move or copy "entry_points.txt" into project directory or workspace directory of the project. While evaluating the project, the tool will ignore the explicit entry points which are added manually and recognize the explicit entry points through the file automatically.
1919

2020
### Limitations
2121

@@ -41,10 +41,17 @@ You should have the following projects in your workspace:
4141

4242
### Running the Evaluator
4343

44-
[annotations]: https://github.com/ponder-lab/edu.cuny.hunter.streamrefactoring.annotations
44+
#### Configuring the Evaluation
45+
46+
A file named `eval.properties` can be placed at the project root. The following keys are available:
47+
48+
Key | Value Type | Description
49+
---------------- | ---------- | ----------
50+
nToUseForStreams | Integer | The value of N to use while building the nCFA for stream types.
4551

4652
### Further Information
4753

4854
See the [wiki][wiki] for further information.
4955

5056
[wiki]: https://github.com/ponder-lab/Java-8-Stream-Refactoring/wiki
57+
[annotations]: https://github.com/ponder-lab/edu.cuny.hunter.streamrefactoring.annotations

edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/PreconditionFailure.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,8 @@ public enum PreconditionFailure {
1919
CURRENTLY_NOT_HANDLED(14), // should just be #97 currently.
2020
STREAM_CODE_NOT_REACHABLE(15), // either pivotal code isn't reachable or
2121
// entry points are misconfigured.
22-
NO_ENTRY_POINT(16); // user didn't specify entry points.
22+
NO_ENTRY_POINT(16), // user didn't specify entry points.
23+
NO_APPLICATION_CODE_IN_CALL_STRINGS(17); // N may be too small.
2324

2425
private int code;
2526

edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Stream.java

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959
import com.ibm.wala.types.TypeReference;
6060
import com.ibm.wala.util.CancelException;
6161

62+
import edu.cuny.hunter.streamrefactoring.core.safe.NoApplicationCodeExistsInCallStringsException;
6263
import edu.cuny.hunter.streamrefactoring.core.utils.LoggerNames;
6364
import edu.cuny.hunter.streamrefactoring.core.utils.Util;
6465
import edu.cuny.hunter.streamrefactoring.core.wala.EclipseProjectAnalysisEngine;
@@ -422,18 +423,33 @@ protected Ordering getInitialOrdering() {
422423
}
423424

424425
public InstanceKey getInstanceKey(Collection<InstanceKey> trackedInstances,
425-
EclipseProjectAnalysisEngine<InstanceKey> engine) throws InvalidClassFileException, IOException,
426-
CoreException, InstanceKeyNotFoundException, UnhandledCaseException {
427-
if (instanceKey == null) {
428-
instanceKey = this.getInstructionForCreation(engine)
429-
.flatMap(instruction -> trackedInstances.stream()
430-
.filter(ik -> instanceKeyCorrespondsWithInstantiationInstruction(ik, instruction,
431-
this.getEnclosingMethodReference(), engine.getCallGraph()))
432-
.findFirst())
433-
.orElseThrow(() -> new InstanceKeyNotFoundException("Can't find instance key for: "
434-
+ this.getCreation() + " using tracked instances: " + trackedInstances));
426+
EclipseProjectAnalysisEngine<InstanceKey> engine)
427+
throws InvalidClassFileException, IOException, CoreException, InstanceKeyNotFoundException,
428+
UnhandledCaseException, NoApplicationCodeExistsInCallStringsException {
429+
// if not present.
430+
if (this.instanceKey == null)
431+
// compute it.
432+
this.instanceKey = computeInstanceKey(trackedInstances, engine);
433+
return this.instanceKey;
434+
}
435+
436+
protected InstanceKey computeInstanceKey(Collection<InstanceKey> trackedInstances,
437+
EclipseProjectAnalysisEngine<InstanceKey> engine)
438+
throws InvalidClassFileException, IOException, CoreException, UnhandledCaseException,
439+
NoApplicationCodeExistsInCallStringsException, InstanceKeyNotFoundException {
440+
Optional<SSAInvokeInstruction> instructionForCreation = this.getInstructionForCreation(engine);
441+
442+
if (instructionForCreation.isPresent()) {
443+
SSAInvokeInstruction instruction = instructionForCreation.get();
444+
445+
for (InstanceKey ik : trackedInstances)
446+
if (instanceKeyCorrespondsWithInstantiationInstruction(ik, instruction,
447+
this.getEnclosingMethodReference(), engine))
448+
return ik;
435449
}
436-
return instanceKey;
450+
451+
throw new InstanceKeyNotFoundException(
452+
"Can't find instance key for: " + this.getCreation() + " using tracked instances: " + trackedInstances);
437453
}
438454

439455
Optional<SSAInvokeInstruction> getInstructionForCreation(EclipseProjectAnalysisEngine<InstanceKey> engine)

edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/StreamAnalyzer.java

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
import java.util.Set;
1717
import java.util.logging.Level;
1818
import java.util.logging.Logger;
19+
import java.util.stream.BaseStream;
1920
import java.util.stream.Collectors;
2021

2122
import org.eclipse.core.runtime.CoreException;
@@ -50,6 +51,8 @@ public class StreamAnalyzer extends ASTVisitor {
5051

5152
private static final Logger LOGGER = Logger.getLogger(LoggerNames.LOGGER_NAME);
5253

54+
private static final int N_FOR_STREAMS_DEFAULT = 2;
55+
5356
private static final String ENTRY_POINT_FILENAME = "entry_points.txt";
5457

5558
private static void addImplicitEntryPoints(Collection<Entrypoint> target, Iterable<Entrypoint> source) {
@@ -73,6 +76,11 @@ private static void addImplicitEntryPoints(Collection<Entrypoint> target, Iterab
7376

7477
private Set<Stream> streamSet = new HashSet<>();
7578

79+
/**
80+
* The N to use for instances of {@link BaseStream} in the nCFA.
81+
*/
82+
private int nForStreams = N_FOR_STREAMS_DEFAULT;
83+
7684
public StreamAnalyzer() {
7785
this(false);
7886
}
@@ -81,25 +89,42 @@ public StreamAnalyzer(boolean visitDocTags) {
8189
super(visitDocTags);
8290
}
8391

92+
public StreamAnalyzer(boolean visitDocTags, int nForStreams) {
93+
super(visitDocTags);
94+
this.nForStreams = nForStreams;
95+
}
96+
8497
public StreamAnalyzer(boolean visitDocTags, boolean findImplicitEntryPoints) {
8598
this(visitDocTags);
8699
this.findImplicitEntryPoints = findImplicitEntryPoints;
87100
}
88101

102+
public StreamAnalyzer(boolean visitDocTags, int nForStreams, boolean findImplicitEntryPoints) {
103+
this(visitDocTags, findImplicitEntryPoints);
104+
this.nForStreams = nForStreams;
105+
}
106+
89107
public StreamAnalyzer(boolean visitDocTags, boolean findImplicitEntryPoints, boolean findImplicitTestEntryPoints,
90108
boolean findImplicitBenchmarkEntryPoints) {
91109
this(visitDocTags, findImplicitEntryPoints);
92110
this.findImplicitTestEntryPoints = findImplicitTestEntryPoints;
93111
this.findImplicitBenchmarkEntryPoints = findImplicitBenchmarkEntryPoints;
94112
}
95113

114+
public StreamAnalyzer(boolean visitDocTags, int nForStreams, boolean findImplicitEntryPoints,
115+
boolean findImplicitTestEntryPoints, boolean findImplicitBenchmarkEntryPoints) {
116+
this(visitDocTags, findImplicitEntryPoints, findImplicitTestEntryPoints, findImplicitBenchmarkEntryPoints);
117+
this.nForStreams = nForStreams;
118+
}
119+
96120
/**
97121
* Analyzes this {@link StreamAnalyzer}'s streams.
98122
*
99123
* @return A {@link Map} of project's analyzed along with the entry points used.
100124
* @see #analyze(Optional).
101125
*/
102126
public Map<IJavaProject, Collection<Entrypoint>> analyze() throws CoreException {
127+
<<<<<<< HEAD
103128
return this.analyze(Optional.empty());
104129
}
105130

@@ -112,6 +137,8 @@ public Map<IJavaProject, Collection<Entrypoint>> analyze() throws CoreException
112137
* @see #analyze().
113138
*/
114139
public Map<IJavaProject, Collection<Entrypoint>> analyze(Optional<TimeCollector> collector) throws CoreException {
140+
LOGGER.info(() -> "Using N = " + this.getNForStreams() + ".");
141+
115142
Map<IJavaProject, Collection<Entrypoint>> ret = new HashMap<>();
116143

117144
// collect the projects to be analyzed.
@@ -126,7 +153,7 @@ public Map<IJavaProject, Collection<Entrypoint>> analyze(Optional<TimeCollector>
126153
collector.ifPresent(TimeCollector::start);
127154
EclipseProjectAnalysisEngine<InstanceKey> engine = null;
128155
try {
129-
engine = new EclipseProjectAnalysisEngine<>(project);
156+
engine = new EclipseProjectAnalysisEngine<>(project, this.getNForStreams());
130157
engine.buildAnalysisScope();
131158
} catch (IOException e) {
132159
LOGGER.log(Level.SEVERE, "Could not create analysis engine for: " + project.getElementName(), e);
@@ -401,4 +428,12 @@ public boolean visit(MethodInvocation node) {
401428

402429
return super.visit(node);
403430
}
431+
432+
public int getNForStreams() {
433+
return nForStreams;
434+
}
435+
436+
protected void setNForStreams(int nForStreams) {
437+
this.nForStreams = nForStreams;
438+
}
404439
}

edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/StreamStateMachine.java

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
import com.ibm.wala.util.strings.Atom;
8383

8484
import edu.cuny.hunter.streamrefactoring.core.safe.ModifiedBenignOracle;
85+
import edu.cuny.hunter.streamrefactoring.core.safe.NoApplicationCodeExistsInCallStringsException;
8586
import edu.cuny.hunter.streamrefactoring.core.safe.TypestateSolverFactory;
8687
import edu.cuny.hunter.streamrefactoring.core.utils.LoggerNames;
8788
import edu.cuny.hunter.streamrefactoring.core.wala.CallStringWithReceivers;
@@ -745,46 +746,26 @@ private void discoverPossibleSideEffects(EclipseProjectAnalysisEngine<InstanceKe
745746
continue;
746747

747748
CallStringWithReceivers callString = Util.getCallString(instance);
748-
CallSiteReference[] callSiteRefs = callString.getCallSiteRefs();
749-
assert callSiteRefs.length == 2 : "Expecting call sites two-deep.";
749+
assert callString.getMethods().length >= 1 : "Expecting call sites at least one-deep.";
750750

751-
// get the target of the caller.
752-
MethodReference callerDeclaredTarget = callSiteRefs[1].getDeclaredTarget();
753-
754-
// get it's IR.
755-
IMethod callerTargetMethod = engine.getClassHierarchy().resolveMethod(callerDeclaredTarget);
756-
boolean fallback = false;
757-
758-
if (callerTargetMethod == null) {
759-
LOGGER.warning("Cannot resolve caller declared target method: " + callerDeclaredTarget);
760-
761-
// fall back.
762-
callerTargetMethod = callString.getMethods()[1];
763-
LOGGER.warning("Falling back to method: " + callerTargetMethod);
764-
fallback = true;
765-
}
766-
767-
IR ir = engine.getCache().getIR(callerTargetMethod);
751+
IR ir = engine.getCache().getIR(callString.getMethods()[0]);
768752

769753
if (ir == null) {
770-
LOGGER.warning("Can't find IR for target: " + callerTargetMethod);
754+
LOGGER.warning("Can't find IR for target: " + callString.getMethods()[0]);
771755
continue; // next instance.
772756
}
773757

774758
// get calls to the caller target.
775-
// if we are falling back, use index 1, otherwise stick with index
776-
// 0.
777-
int callSiteRefsInx = fallback ? 1 : 0;
778-
SSAAbstractInvokeInstruction[] calls = ir.getCalls(callSiteRefs[callSiteRefsInx]);
759+
SSAAbstractInvokeInstruction[] calls = ir.getCalls(callString.getCallSiteRefs()[0]);
779760
assert calls.length == 1 : "Are we only expecting one call here?";
780761

781762
// I guess we're only interested in ones with a single behavioral
782763
// parameter (the first parameter is implicit).
783764
if (calls[0].getNumberOfUses() == 2) {
784765
// get the use of the first parameter.
785766
int use = calls[0].getUse(1);
786-
this.discoverLambdaSideEffects(engine, mod, Collections.singleton(instance), callerDeclaredTarget, ir,
787-
use);
767+
this.discoverLambdaSideEffects(engine, mod, Collections.singleton(instance),
768+
callString.getMethods()[0].getReference(), ir, use);
788769
}
789770
}
790771
}
@@ -866,18 +847,28 @@ private void fillInstanceToStreamMap(Set<Stream> streamSet, EclipseProjectAnalys
866847
try {
867848
instanceKey = stream.getInstanceKey(this.trackedInstances, engine);
868849
} catch (InstanceKeyNotFoundException e) {
869-
LOGGER.log(Level.WARNING, "Encountered unreachable code while processing: " + stream.getCreation(), e);
850+
LOGGER.log(Level.WARNING,
851+
"Encountered unreachable code while processing: " + stream.getCreation() + ".", e);
870852
stream.addStatusEntry(PreconditionFailure.STREAM_CODE_NOT_REACHABLE,
871853
"Either pivital code isn't reachable for stream: " + stream.getCreation()
872854
+ " or entry points are misconfigured.");
873855
++skippedStreams;
874856
continue; // next stream.
875857
} catch (UnhandledCaseException e) {
876-
String msg = "Encountered possible unhandled case (AIC #155) while processing: " + stream.getCreation();
858+
String msg = "Encountered possible unhandled case (AIC #155) while processing: " + stream.getCreation()
859+
+ ".";
877860
LOGGER.log(Level.WARNING, msg, e);
878861
stream.addStatusEntry(PreconditionFailure.CURRENTLY_NOT_HANDLED, msg);
879862
++skippedStreams;
880863
continue; // next stream.
864+
} catch (NoApplicationCodeExistsInCallStringsException e) {
865+
LOGGER.log(Level.WARNING, "Did not encounter application code in call strings while processing: "
866+
+ stream.getCreation() + ".", e);
867+
stream.addStatusEntry(PreconditionFailure.NO_APPLICATION_CODE_IN_CALL_STRINGS,
868+
"No application code in the call strings generated for stream: " + stream.getCreation()
869+
+ " was found. The maximum call string length may need to be increased.");
870+
++skippedStreams;
871+
continue; // next stream.
881872
}
882873

883874
// add the mapping.

edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/analysis/Util.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@
6060
import com.ibm.wala.ssa.SSAInvokeInstruction;
6161
import com.ibm.wala.ssa.SSAPhiInstruction;
6262
import com.ibm.wala.ssa.Value;
63+
import com.ibm.wala.types.ClassLoaderReference;
6364
import com.ibm.wala.types.MethodReference;
6465
import com.ibm.wala.types.TypeName;
6566
import com.ibm.wala.types.TypeReference;
@@ -568,6 +569,7 @@ else if (Modifier.isAbstract(clazz.getModifiers()))
568569
else
569570
return false;
570571
}
572+
571573

572574
public static boolean isBaseStream(IClass clazz) {
573575
return Util.isType(clazz, "java/util/stream", "BaseStream");
@@ -706,4 +708,24 @@ public static TypeReference getEvaluationType(IMethod method) {
706708
// use the return type.
707709
return method.getReturnType();
708710
}
709-
}
711+
712+
/**
713+
* Returns the index of the first {@link IMethod} in methods that is client
714+
* code.
715+
*
716+
* @param methods
717+
* The {@link IMethod}s in question.
718+
* @return The index of the first {@link IMethod} that is client code and -1 if
719+
* none found.
720+
*/
721+
public static int findIndexOfFirstClientMethod(IMethod[] methods) {
722+
for (int i = 0; i < methods.length; i++) {
723+
IMethod meth = methods[i];
724+
725+
if (meth.getDeclaringClass().getClassLoader().getReference().equals(ClassLoaderReference.Application))
726+
return i;
727+
}
728+
729+
return -1; // not found.
730+
}
731+
}

0 commit comments

Comments
 (0)