Skip to content

Commit 48c91b9

Browse files
authored
Create defined class to perform analysis within thread (#338)
When refactoring from an Anonymous class to a lambda, an infinite recursion occurred because each analysis was required to then fork and create a new analysis when it was done because it defined a new anonymous class. This change defines the class specifically to avoid it analyzing itself. A follow up should be to filter anonymous classes unrelated to ParSeq.
1 parent ed54dc8 commit 48c91b9

2 files changed

Lines changed: 45 additions & 17 deletions

File tree

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
version=5.1.14
1+
version=5.1.15
22
group=com.linkedin.parseq
33
org.gradle.parallel=true

subprojects/parseq-lambda-names/src/main/java/com/linkedin/parseq/lambda/ASMBasedTaskDescriptor.java

Lines changed: 44 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,49 @@ private static void add(String lambdaClassName, String description) {
183183

184184
public static class Analyzer implements ClassFileTransformer {
185185

186+
/**
187+
* Defining this class as not anonymous to avoid analyzing the runnable that is created to
188+
* perform analysis. Without this, it is easy for an infinite loop to occur when using a lambda,
189+
* which would result in a {@link StackOverflowError}, because when performing an analysis of the lambda
190+
* would then require a new analysis of a new lambda.
191+
*
192+
* TODO: Avoid analyzing anonymous classes unrelated to parseq
193+
*/
194+
static class AnalyzerRunnable implements Runnable {
195+
private final byte[] byteCode;
196+
private final ClassLoader loader;
197+
private final Exception e;
198+
199+
private AnalyzerRunnable(byte[] byteCode, ClassLoader loader, Exception e) {
200+
this.byteCode = byteCode;
201+
this.loader = loader;
202+
this.e = e;
203+
}
204+
205+
public static AnalyzerRunnable of(byte[] byteCode, ClassLoader loader, Exception e) {
206+
return new AnalyzerRunnable(byteCode, loader, e);
207+
}
208+
209+
@Override
210+
public void run() {
211+
try {
212+
doAnalyze(byteCode, loader, e);
213+
} catch (Throwable t) {
214+
/*
215+
* We need to catch everything because other
216+
* threads may be blocked on CountDownLatch.
217+
*/
218+
System.out.println("WARNING: Parseq cannot doAnalyze");
219+
t.printStackTrace();
220+
}
221+
if (_count.decrementAndGet() == 0) {
222+
CountDownLatch latch = _latchRef.getAndSet(null);
223+
latch.countDown();
224+
}
225+
226+
}
227+
}
228+
186229
@Override
187230
public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined,
188231
ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {
@@ -205,22 +248,7 @@ public static void analyze(byte[] byteCode, ClassLoader loader) {
205248
}
206249
}
207250
final Exception e = new Exception();
208-
ForkJoinPool.commonPool().execute(() -> {
209-
try {
210-
doAnalyze(byteCode, loader, e);
211-
} catch (Throwable t) {
212-
/*
213-
* We need to catch everything because other
214-
* threads may be blocked on CountDownLatch.
215-
*/
216-
System.out.println("WARNING: Parseq cannot doAnalyze");
217-
t.printStackTrace();
218-
}
219-
if (_count.decrementAndGet() == 0) {
220-
CountDownLatch latch = _latchRef.getAndSet(null);
221-
latch.countDown();
222-
}
223-
});
251+
ForkJoinPool.commonPool().execute(AnalyzerRunnable.of(byteCode, loader, e));
224252
}
225253

226254
public static void doAnalyze(byte[] byteCode, ClassLoader loader, Exception exception) {

0 commit comments

Comments
 (0)