You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by su...@apache.org on 2021/03/06 20:40:38 UTC
[groovy] 01/01: GROOVY-9964: Parallelize parsing
This is an automated email from the ASF dual-hosted git repository.
sunlan pushed a commit to branch GROOVY-9964
in repository https://gitbox.apache.org/repos/asf/groovy.git
commit 281456cdb3cb9cda7908c223d0ae5ef2e2b11373
Author: Daniel Sun <su...@apache.org>
AuthorDate: Sun Mar 7 04:36:13 2021 +0800
GROOVY-9964: Parallelize parsing
---
.../groovy/parser/antlr4/Antlr4ParserPlugin.java | 81 ++++++++++++++++++++--
.../apache/groovy/parser/antlr4/AstBuilder.java | 22 +++---
.../java/org/codehaus/groovy/ast/ModuleNode.java | 4 ++
3 files changed, 90 insertions(+), 17 deletions(-)
diff --git a/src/main/java/org/apache/groovy/parser/antlr4/Antlr4ParserPlugin.java b/src/main/java/org/apache/groovy/parser/antlr4/Antlr4ParserPlugin.java
index 819165e..562b06e 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/Antlr4ParserPlugin.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/Antlr4ParserPlugin.java
@@ -18,8 +18,11 @@
*/
package org.apache.groovy.parser.antlr4;
+import groovy.lang.GroovyRuntimeException;
import org.codehaus.groovy.GroovyBugError;
import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.ErrorCollector;
import org.codehaus.groovy.control.ParserPlugin;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.control.io.StringReaderSource;
@@ -28,6 +31,12 @@ import org.codehaus.groovy.syntax.Reduction;
import java.io.IOException;
import java.io.Reader;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.concurrent.atomic.AtomicReference;
/**
* A parser plugin for the new parser.
@@ -49,12 +58,74 @@ public class Antlr4ParserPlugin implements ParserPlugin {
return null;
}
+ private static final ExecutorService THREAD_POOL = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), new ThreadFactory() {
+ private int seq = 0;
+ @Override
+ public Thread newThread(Runnable r) {
+ Thread t = new Thread(r, "parser-thread-" + seq++);
+ t.setDaemon(true);
+ return t;
+ }
+ });
+
@Override
public ModuleNode buildAST(final SourceUnit sourceUnit, final ClassLoader classLoader, final Reduction cst) {
- AstBuilder builder = new AstBuilder(sourceUnit,
- sourceUnit.getConfiguration().isGroovydocEnabled(),
- sourceUnit.getConfiguration().isRuntimeGroovydocEnabled()
- );
- return builder.buildAST();
+ CountDownLatch countDownLatch = new CountDownLatch(1);
+ AtomicReference<ModuleNode> moduleNodeAtomicReference = new AtomicReference<>();
+ ExceptionHolder<CompilationFailedException> exceptionHolder = new ExceptionHolder<>(countDownLatch);
+ submitParseTask(sourceUnit, countDownLatch, moduleNodeAtomicReference, exceptionHolder, "LL");
+ submitParseTask(sourceUnit, countDownLatch, moduleNodeAtomicReference, exceptionHolder, "SLL");
+
+ ModuleNode moduleNode;
+ try {
+ countDownLatch.await();
+ moduleNode = moduleNodeAtomicReference.get();
+ } catch (InterruptedException e) {
+ throw new GroovyRuntimeException(e);
+ }
+
+ if (null != moduleNode) {
+ moduleNode.setContext(sourceUnit);
+ return moduleNode;
+ }
+ throw exceptionHolder.get();
+ }
+
+ private void submitParseTask(SourceUnit sourceUnit, CountDownLatch countDownLatch, AtomicReference<ModuleNode> moduleNodeAtomicReference, ExceptionHolder<CompilationFailedException> exceptionHolder, String predictionModeName) {
+ THREAD_POOL.submit(() -> {
+ SourceUnit su = new SourceUnit(sourceUnit.getName(), sourceUnit.getSource(), sourceUnit.getConfiguration(), sourceUnit.getClassLoader(), new ErrorCollector(sourceUnit.getConfiguration()));
+ AstBuilder builder = new AstBuilder(su,
+ su.getConfiguration().isGroovydocEnabled(),
+ su.getConfiguration().isRuntimeGroovydocEnabled()
+ );
+
+ try {
+ moduleNodeAtomicReference.set(builder.buildAST(predictionModeName));
+ countDownLatch.countDown();
+ } catch (CompilationFailedException ex) {
+ exceptionHolder.set(ex);
+ }
+ });
+ }
+
+ private static class ExceptionHolder<T extends Exception> {
+ private final AtomicReference<T> ar = new AtomicReference<>();
+ private final AtomicInteger count = new AtomicInteger(0);
+ private final CountDownLatch countDownLatch;
+
+ private ExceptionHolder(CountDownLatch countDownLatch) {
+ this.countDownLatch = countDownLatch;
+ }
+
+ public final void set(T compilationFailedException) {
+ ar.set(compilationFailedException);
+ if (2 == count.incrementAndGet()) {
+ countDownLatch.countDown();
+ }
+ }
+
+ public T get() {
+ return ar.get();
+ }
}
}
diff --git a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
index 669be8a..720e6fa 100644
--- a/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
+++ b/src/main/java/org/apache/groovy/parser/antlr4/AstBuilder.java
@@ -371,21 +371,19 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
return charStream;
}
- private GroovyParserRuleContext buildCST() throws CompilationFailedException {
+ private GroovyParserRuleContext buildCST(final String predictionModeName) throws CompilationFailedException {
GroovyParserRuleContext result;
try {
// parsing have to wait util clearing is complete.
AtnManager.READ_LOCK.lock();
try {
- result = buildCST(PredictionMode.SLL);
- } catch (Throwable t) {
- // if some syntax error occurred in the lexer, no need to retry the powerful LL mode
- if (t instanceof GroovySyntaxError && GroovySyntaxError.LEXER == ((GroovySyntaxError) t).getSource()) {
- throw t;
+ PredictionMode predictionMode = PredictionMode.valueOf(predictionModeName);
+ if (PredictionMode.SLL == predictionMode) {
+ result = doBuildCST(PredictionMode.SLL);
+ } else {
+ result = doBuildCST(PredictionMode.LL);
}
-
- result = buildCST(PredictionMode.LL);
} finally {
AtnManager.READ_LOCK.unlock();
}
@@ -396,10 +394,10 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
return result;
}
- private GroovyParserRuleContext buildCST(final PredictionMode predictionMode) {
+ private GroovyParserRuleContext doBuildCST(final PredictionMode predictionMode) {
parser.getInterpreter().setPredictionMode(predictionMode);
- if (PredictionMode.SLL.equals(predictionMode)) {
+ if (PredictionMode.SLL == predictionMode) {
this.removeErrorListeners();
} else {
parser.getInputStream().seek(0);
@@ -423,9 +421,9 @@ public class AstBuilder extends GroovyParserBaseVisitor<Object> {
return cfe;
}
- public ModuleNode buildAST() {
+ public ModuleNode buildAST(final String predictionModeName) {
try {
- return (ModuleNode) this.visit(this.buildCST());
+ return (ModuleNode) this.visit(this.buildCST(predictionModeName));
} catch (Throwable t) {
throw convertException(t);
}
diff --git a/src/main/java/org/codehaus/groovy/ast/ModuleNode.java b/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
index fedec5a..fb9c1a9 100644
--- a/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
@@ -508,4 +508,8 @@ public class ModuleNode extends ASTNode {
public BlockStatement getStatementBlock() {
return statementBlock;
}
+
+ public void setContext(SourceUnit sourceUnit) {
+ this.context = sourceUnit;
+ }
}