Skip to content

Commit e48712a

Browse files
committed
Fix #176.
New precondition failure for when N is too small. Also, remove workaround for #80 (it's not accurate).
1 parent d8c0b22 commit e48712a

File tree

7 files changed

+111
-37
lines changed

7 files changed

+111
-37
lines changed

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.getCallGraph()))
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/StreamStateMachine.java

Lines changed: 13 additions & 2 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;
@@ -866,18 +867,28 @@ private void fillInstanceToStreamMap(Set<Stream> streamSet, EclipseProjectAnalys
866867
try {
867868
instanceKey = stream.getInstanceKey(this.trackedInstances, engine);
868869
} catch (InstanceKeyNotFoundException e) {
869-
LOGGER.log(Level.WARNING, "Encountered unreachable code while processing: " + stream.getCreation(), e);
870+
LOGGER.log(Level.WARNING,
871+
"Encountered unreachable code while processing: " + stream.getCreation() + ".", e);
870872
stream.addStatusEntry(PreconditionFailure.STREAM_CODE_NOT_REACHABLE,
871873
"Either pivital code isn't reachable for stream: " + stream.getCreation()
872874
+ " or entry points are misconfigured.");
873875
++skippedStreams;
874876
continue; // next stream.
875877
} catch (UnhandledCaseException e) {
876-
String msg = "Encountered possible unhandled case (AIC #155) while processing: " + stream.getCreation();
878+
String msg = "Encountered possible unhandled case (AIC #155) while processing: " + stream.getCreation()
879+
+ ".";
877880
LOGGER.log(Level.WARNING, msg, e);
878881
stream.addStatusEntry(PreconditionFailure.CURRENTLY_NOT_HANDLED, msg);
879882
++skippedStreams;
880883
continue; // next stream.
884+
} catch (NoApplicationCodeExistsInCallStringsException e) {
885+
LOGGER.log(Level.WARNING, "Did not encounter application code in call strings while processing: "
886+
+ stream.getCreation() + ".", e);
887+
stream.addStatusEntry(PreconditionFailure.NO_APPLICATION_CODE_IN_CALL_STRINGS,
888+
"No application code in the call strings generated for stream: " + stream.getCreation()
889+
+ " was found. The maximum call string length may need to be increased.");
890+
++skippedStreams;
891+
continue; // next stream.
881892
}
882893

883894
// add the mapping.

edu.cuny.hunter.streamrefactoring.core/src/edu/cuny/hunter/streamrefactoring/core/safe/InstructionBasedSolver.java

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.Collection;
44
import java.util.HashSet;
5+
import java.util.logging.Level;
56
import java.util.logging.Logger;
67

78
import com.ibm.safe.internal.exceptions.PropertiesException;
@@ -43,9 +44,14 @@ protected Collection<InstanceKey> computeTrackedInstances() throws PropertiesExc
4344

4445
for (InstanceKey instanceKey : trackedInstancesByType) {
4546
LOGGER.info("Examining instance: " + instanceKey);
46-
if (Util.instanceKeyCorrespondsWithInstantiationInstruction(instanceKey, this.getInstruction(), null,
47-
this.getCallGraph()))
48-
ret.add(instanceKey);
47+
try {
48+
if (Util.instanceKeyCorrespondsWithInstantiationInstruction(instanceKey, this.getInstruction(), null,
49+
this.getCallGraph()))
50+
ret.add(instanceKey);
51+
} catch (NoApplicationCodeExistsInCallStringsException e) {
52+
LOGGER.log(Level.SEVERE, e, () -> "Encountered NoApplicationCodeExistsInCallStringsException.");
53+
throw new RuntimeException(e);
54+
}
4955
}
5056

5157
if (ret.size() != 1)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package edu.cuny.hunter.streamrefactoring.core.safe;
2+
3+
public class NoApplicationCodeExistsInCallStringsException extends Exception {
4+
5+
public NoApplicationCodeExistsInCallStringsException(String message) {
6+
super(message);
7+
}
8+
9+
public NoApplicationCodeExistsInCallStringsException(Throwable cause) {
10+
super(cause);
11+
}
12+
13+
public NoApplicationCodeExistsInCallStringsException(String message, Throwable cause) {
14+
super(message, cause);
15+
}
16+
17+
public NoApplicationCodeExistsInCallStringsException(String message, Throwable cause, boolean enableSuppression,
18+
boolean writableStackTrace) {
19+
super(message, cause, enableSuppression, writableStackTrace);
20+
}
21+
}

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

Lines changed: 37 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
import java.util.logging.Logger;
55

66
import com.ibm.wala.classLoader.CallSiteReference;
7+
import com.ibm.wala.classLoader.IClassLoader;
78
import com.ibm.wala.classLoader.IMethod;
89
import com.ibm.wala.classLoader.NewSiteReference;
910
import com.ibm.wala.ipa.callgraph.CGNode;
@@ -13,28 +14,33 @@
1314
import com.ibm.wala.ipa.callgraph.propagation.cfa.CallString;
1415
import com.ibm.wala.ipa.callgraph.propagation.cfa.CallStringContextSelector;
1516
import com.ibm.wala.ssa.SSAInvokeInstruction;
17+
import com.ibm.wala.types.ClassLoaderReference;
1618
import com.ibm.wala.types.MethodReference;
1719
import com.ibm.wala.types.TypeName;
1820
import com.ibm.wala.util.collections.Pair;
1921
import com.ibm.wala.util.strings.Atom;
2022

2123
import edu.cuny.hunter.streamrefactoring.core.utils.LoggerNames;
24+
import edu.cuny.hunter.streamrefactoring.core.wala.nCFAContextWithReceiversSelector;
2225

2326
public class Util {
2427

2528
/**
2629
* The {@link TypeName} of the type {@link java.util.Arrays}.
2730
*/
31+
@SuppressWarnings("unused")
2832
private static final TypeName ARRAYS_TYPE_NAME = TypeName.string2TypeName("Ljava/util/Arrays");
2933

3034
/**
3135
* {@link Atom} corresponding the the stream() method.
3236
*/
37+
@SuppressWarnings("unused")
3338
private static final Atom STREAM_METHOD_NAME_ATOM = Atom.findOrCreateAsciiAtom("stream");
3439

3540
/**
3641
* The {@link TypeName} for the type {@link java.util.stream.StreamSupport}.
3742
*/
43+
@SuppressWarnings("unused")
3844
private static final TypeName STREAM_SUPPORT_TYPE_NAME = TypeName
3945
.string2TypeName("Ljava/util/stream/StreamSupport");
4046

@@ -54,16 +60,23 @@ public class Util {
5460
* The corresponding call graph.
5561
* @return True iff the given instruction was used to instantiate the given
5662
* instance key according to the given call graph.
63+
* @throws NoApplicationCodeExistsInCallStringsException
64+
* Iff application code was not found while processing call strings.
5765
*/
5866
public static boolean instanceKeyCorrespondsWithInstantiationInstruction(InstanceKey instanceKey,
59-
SSAInvokeInstruction instruction, MethodReference instructionEnclosingMethod, CallGraph callGraph) {
67+
SSAInvokeInstruction instruction, MethodReference instructionEnclosingMethod, CallGraph callGraph)
68+
throws NoApplicationCodeExistsInCallStringsException {
6069
// Creation sites for the instance with the given key in the given call
6170
// graph.
6271
Iterator<Pair<CGNode, NewSiteReference>> creationSites = instanceKey.getCreationSites(callGraph);
6372

6473
CallSiteReference instructionCallSite = instruction.getCallSite();
6574
LOGGER.fine("instruction call site is: " + instructionCallSite);
6675

76+
// did we see an application code entity in a call string? If not, this could
77+
// indicate that N is too small.
78+
boolean applicationCodeInCallString = false;
79+
6780
// for each creation site.
6881
while (creationSites.hasNext()) {
6982
Pair<CGNode, NewSiteReference> pair = creationSites.next();
@@ -89,6 +102,21 @@ public static boolean instanceKeyCorrespondsWithInstantiationInstruction(Instanc
89102
IMethod method = methods[i];
90103
LOGGER.fine("Method at " + i + " is: " + method);
91104

105+
// if we haven't encountered application code in the call string yet.
106+
if (!applicationCodeInCallString) {
107+
// get the class loaders.
108+
ClassLoaderReference callSiteReferenceClassLoader = callSiteReference.getDeclaredTarget()
109+
.getDeclaringClass().getClassLoader();
110+
IClassLoader methodClassLoader = method.getDeclaringClass().getClassLoader();
111+
112+
// if either the call site reference class loader or the (enclosing) method
113+
// class loader is of type Application.
114+
if (callSiteReferenceClassLoader.equals(ClassLoaderReference.Application)
115+
|| methodClassLoader.equals(ClassLoaderReference.Application))
116+
// then, we've seen application code.
117+
applicationCodeInCallString = true;
118+
}
119+
92120
// if the call site reference equals the call site corresponding
93121
// to the creation instruction.
94122
if (callSiteReference.equals(instructionCallSite)
@@ -97,27 +125,18 @@ public static boolean instanceKeyCorrespondsWithInstantiationInstruction(Instanc
97125
+ instruction + ".");
98126
return true;
99127
}
100-
// workaround #80.
101-
else if (callSiteReference.getProgramCounter() == instructionCallSite.getProgramCounter()) {
102-
// compare declared targets.
103-
MethodReference callSiteDeclaredTarget = callSiteReference.getDeclaredTarget();
104-
TypeName callSiteTargetDeclaringClassName = callSiteDeclaredTarget.getDeclaringClass().getName();
105-
106-
MethodReference instructionCallDeclaredTarget = instructionCallSite.getDeclaredTarget();
107-
TypeName instructionTargetDeclaringClassName = instructionCallDeclaredTarget.getDeclaringClass()
108-
.getName();
109-
110-
if (callSiteTargetDeclaringClassName.equals(instructionTargetDeclaringClassName)
111-
&& (callSiteTargetDeclaringClassName.equals(ARRAYS_TYPE_NAME)
112-
|| callSiteTargetDeclaringClassName.equals(STREAM_SUPPORT_TYPE_NAME))
113-
&& callSiteDeclaredTarget.getName().equals(instructionCallDeclaredTarget.getName())
114-
&& callSiteDeclaredTarget.getName().equals(STREAM_METHOD_NAME_ATOM))
115-
return true;
116-
}
117128
}
118129
}
119130
LOGGER.fine("No match found. Instance key: " + instanceKey + " does not correspond with instruction: "
120131
+ instruction + ".");
132+
133+
// if we did not encounter application code in the call strings.
134+
if (!applicationCodeInCallString)
135+
throw new NoApplicationCodeExistsInCallStringsException(
136+
"Could not find application code in call string while processing instance key: " + instanceKey
137+
+ " and instruction: " + instruction + ". This may indicate that the current value of N ("
138+
+ nCFAContextWithReceiversSelector.CONTEXT_LENGTH_FOR_STREAMS + ") is too small.");
139+
121140
return false;
122141
}
123142

edu.cuny.hunter.streamrefactoring.tests/test cases/edu/cuny/hunter/streamrefactoring/ui/tests/ConvertStreamToParallelRefactoringTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -383,8 +383,8 @@ public void testEntrySet4() throws Exception {
383383
public void testArraysStream() throws Exception {
384384
helper(new StreamAnalysisExpectedResult("Arrays.stream(new Object[1])",
385385
Collections.singleton(ExecutionMode.SEQUENTIAL), EnumSet.of(Ordering.ORDERED), false, false, false,
386-
EnumSet.of(TransformationAction.CONVERT_TO_PARALLEL), PreconditionSuccess.P2,
387-
Refactoring.CONVERT_SEQUENTIAL_STREAM_TO_PARALLEL, RefactoringStatus.OK, Collections.emptySet()));
386+
null, null, null, RefactoringStatus.ERROR,
387+
EnumSet.of(PreconditionFailure.NO_APPLICATION_CODE_IN_CALL_STRINGS)));
388388
}
389389

390390
public void testConstructor() throws Exception {

0 commit comments

Comments
 (0)