Skip to content

Commit ee306f8

Browse files
authored
Merge branch 'master' into entry_points_txt
2 parents d584ae2 + 3a10355 commit ee306f8

File tree

20 files changed

+522
-126
lines changed

20 files changed

+522
-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: 35 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import java.util.Set;
1616
import java.util.logging.Level;
1717
import java.util.logging.Logger;
18+
import java.util.stream.BaseStream;
1819
import java.util.stream.Collectors;
1920

2021
import org.eclipse.core.runtime.CoreException;
@@ -48,6 +49,8 @@ public class StreamAnalyzer extends ASTVisitor {
4849

4950
private static final Logger LOGGER = Logger.getLogger(LoggerNames.LOGGER_NAME);
5051

52+
private static final int N_FOR_STREAMS_DEFAULT = 2;
53+
5154
private static final String ENTRY_POINT_FILENAME = "entry_points.txt";
5255

5356
private static void addImplicitEntryPoints(Collection<Entrypoint> target, Iterable<Entrypoint> source) {
@@ -71,6 +74,11 @@ private static void addImplicitEntryPoints(Collection<Entrypoint> target, Iterab
7174

7275
private Set<Stream> streamSet = new HashSet<>();
7376

77+
/**
78+
* The N to use for instances of {@link BaseStream} in the nCFA.
79+
*/
80+
private int nForStreams = N_FOR_STREAMS_DEFAULT;
81+
7482
public StreamAnalyzer() {
7583
this(false);
7684
}
@@ -79,24 +87,42 @@ public StreamAnalyzer(boolean visitDocTags) {
7987
super(visitDocTags);
8088
}
8189

90+
public StreamAnalyzer(boolean visitDocTags, int nForStreams) {
91+
super(visitDocTags);
92+
this.nForStreams = nForStreams;
93+
}
94+
8295
public StreamAnalyzer(boolean visitDocTags, boolean findImplicitEntryPoints) {
8396
this(visitDocTags);
8497
this.findImplicitEntryPoints = findImplicitEntryPoints;
8598
}
8699

100+
public StreamAnalyzer(boolean visitDocTags, int nForStreams, boolean findImplicitEntryPoints) {
101+
this(visitDocTags, findImplicitEntryPoints);
102+
this.nForStreams = nForStreams;
103+
}
104+
87105
public StreamAnalyzer(boolean visitDocTags, boolean findImplicitEntryPoints, boolean findImplicitTestEntryPoints,
88106
boolean findImplicitBenchmarkEntryPoints) {
89107
this(visitDocTags, findImplicitEntryPoints);
90108
this.findImplicitTestEntryPoints = findImplicitTestEntryPoints;
91109
this.findImplicitBenchmarkEntryPoints = findImplicitBenchmarkEntryPoints;
92110
}
93111

112+
public StreamAnalyzer(boolean visitDocTags, int nForStreams, boolean findImplicitEntryPoints,
113+
boolean findImplicitTestEntryPoints, boolean findImplicitBenchmarkEntryPoints) {
114+
this(visitDocTags, findImplicitEntryPoints, findImplicitTestEntryPoints, findImplicitBenchmarkEntryPoints);
115+
this.nForStreams = nForStreams;
116+
}
117+
94118
/**
95119
* Analyzes this {@link StreamAnalyzer}'s streams.
96120
*
97121
* @return {@link Map} of project's analyzed along with the entry points used.
98122
*/
99123
public Map<IJavaProject, Collection<Entrypoint>> analyze() throws CoreException {
124+
LOGGER.info(() -> "Using N = " + this.getNForStreams());
125+
100126
Map<IJavaProject, Collection<Entrypoint>> ret = new HashMap<>();
101127

102128
// collect the projects to be analyzed.
@@ -108,7 +134,7 @@ public Map<IJavaProject, Collection<Entrypoint>> analyze() throws CoreException
108134
// create the analysis engine for the project.
109135
EclipseProjectAnalysisEngine<InstanceKey> engine = null;
110136
try {
111-
engine = new EclipseProjectAnalysisEngine<>(project);
137+
engine = new EclipseProjectAnalysisEngine<>(project, this.getNForStreams());
112138
engine.buildAnalysisScope();
113139
} catch (IOException e) {
114140
LOGGER.log(Level.SEVERE, "Could not create analysis engine for: " + project.getElementName(), e);
@@ -375,4 +401,12 @@ public boolean visit(MethodInvocation node) {
375401

376402
return super.visit(node);
377403
}
404+
405+
public int getNForStreams() {
406+
return nForStreams;
407+
}
408+
409+
protected void setNForStreams(int nForStreams) {
410+
this.nForStreams = nForStreams;
411+
}
378412
}

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+
}

edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/refactorings/ConvertToParallelStreamRefactoringProcessor.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,8 @@ public class ConvertToParallelStreamRefactoringProcessor extends RefactoringProc
7878
*/
7979
private static int loggingLevel = IStatus.WARNING;
8080

81+
private static final int N_FOR_STREAMS_DEFAULT = 2;
82+
8183
@SuppressWarnings("unused")
8284
private static final GroupCategorySet SET_CONVERT_STREAM_TO_PARALLEL = new GroupCategorySet(
8385
new GroupCategory("edu.cuny.hunter.streamrefactoring", //$NON-NLS-1$
@@ -142,6 +144,8 @@ public static void setLoggingLevel(int level) {
142144

143145
private boolean useImplicitTestEntrypoints = false;
144146

147+
private int nForStreams = N_FOR_STREAMS_DEFAULT;
148+
145149
public ConvertToParallelStreamRefactoringProcessor() throws JavaModelException {
146150
this(null, null, false, true, false, false, Optional.empty());
147151
}
@@ -167,12 +171,31 @@ public ConvertToParallelStreamRefactoringProcessor(IJavaProject[] javaProjects,
167171
}
168172
}
169173

174+
public ConvertToParallelStreamRefactoringProcessor(IJavaProject[] javaProjects,
175+
final CodeGenerationSettings settings, boolean layer, int nForStreams, boolean useImplicitEntrypoints,
176+
boolean useImplicitTestEntrypoints, boolean useImplicitBenchmarkEntrypoints,
177+
Optional<IProgressMonitor> monitor) throws JavaModelException {
178+
this(javaProjects, settings, layer, useImplicitEntrypoints, useImplicitTestEntrypoints,
179+
useImplicitBenchmarkEntrypoints, monitor);
180+
try {
181+
this.nForStreams = nForStreams;
182+
} finally {
183+
monitor.ifPresent(IProgressMonitor::done);
184+
}
185+
}
186+
170187
public ConvertToParallelStreamRefactoringProcessor(IJavaProject[] javaProjects,
171188
final CodeGenerationSettings settings, boolean useImplicitJoinpoints, Optional<IProgressMonitor> monitor)
172189
throws JavaModelException {
173190
this(javaProjects, settings, false, useImplicitJoinpoints, false, false, monitor);
174191
}
175192

193+
public ConvertToParallelStreamRefactoringProcessor(IJavaProject[] javaProjects,
194+
final CodeGenerationSettings settings, int nForStreams, boolean useImplicitJoinpoints,
195+
Optional<IProgressMonitor> monitor) throws JavaModelException {
196+
this(javaProjects, settings, false, nForStreams, useImplicitJoinpoints, false, false, monitor);
197+
}
198+
176199
public ConvertToParallelStreamRefactoringProcessor(IJavaProject[] javaProjects,
177200
final CodeGenerationSettings settings, Optional<IProgressMonitor> monitor) throws JavaModelException {
178201
this(javaProjects, settings, false, true, false, false, monitor);
@@ -196,7 +219,7 @@ public RefactoringStatus checkFinalConditions(final IProgressMonitor monitor, fi
196219
SubMonitor subMonitor = SubMonitor.convert(monitor, Messages.CheckingPreconditions,
197220
this.getJavaProjects().length * 1000);
198221
final RefactoringStatus status = new RefactoringStatus();
199-
StreamAnalyzer analyzer = new StreamAnalyzer(false, this.getUseImplicitEntrypoints(),
222+
StreamAnalyzer analyzer = new StreamAnalyzer(false, this.getNForStreams(), this.getUseImplicitEntrypoints(),
200223
this.getUseImplicitTestEntrypoints(), this.getUseImplicitBenchmarkEntrypoints());
201224
this.setStreamSet(analyzer.getStreamSet());
202225

@@ -251,6 +274,14 @@ public RefactoringStatus checkFinalConditions(final IProgressMonitor monitor, fi
251274
}
252275
}
253276

277+
public int getNForStreams() {
278+
return this.nForStreams;
279+
}
280+
281+
public void setNForStreams(int nForStreams) {
282+
this.nForStreams = nForStreams;
283+
}
284+
254285
@Override
255286
public RefactoringStatus checkInitialConditions(IProgressMonitor pm)
256287
throws CoreException, OperationCanceledException {

0 commit comments

Comments
 (0)