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:36:30 UTC
[groovy] branch GROOVY-9964 updated: 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
The following commit(s) were added to refs/heads/GROOVY-9964 by this push:
new 3f9f753 GROOVY-9964: Parallelize parsing
3f9f753 is described below
commit 3f9f753c2ec591e3d39f7e2b242bc1132144bd94
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 | 14 ++--
3 files changed, 93 insertions(+), 24 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..39bda06 100644
--- a/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
+++ b/src/main/java/org/codehaus/groovy/ast/ModuleNode.java
@@ -25,6 +25,7 @@ import org.codehaus.groovy.classgen.GeneratorContext;
import org.codehaus.groovy.control.SourceUnit;
import org.codehaus.groovy.runtime.InvokerHelper;
import org.codehaus.groovy.transform.BaseScriptASTTransformation;
+import org.objectweb.asm.Opcodes;
import java.io.File;
import java.net.URI;
@@ -46,18 +47,13 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.param;
import static org.codehaus.groovy.ast.tools.GeneralUtils.params;
import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
-import static org.objectweb.asm.Opcodes.ACC_ABSTRACT;
-import static org.objectweb.asm.Opcodes.ACC_FINAL;
-import static org.objectweb.asm.Opcodes.ACC_INTERFACE;
-import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
-import static org.objectweb.asm.Opcodes.ACC_STATIC;
/**
* Represents a module, which consists typically of a class declaration
* but could include some imports, some statements and multiple classes
* intermixed with statements like scripts in Python or Ruby
*/
-public class ModuleNode extends ASTNode {
+public class ModuleNode extends ASTNode implements Opcodes {
private List<ClassNode> classes = new LinkedList<>();
private final List<MethodNode> methods = new ArrayList<>();
@@ -403,7 +399,7 @@ public class ModuleNode extends ASTNode {
private MethodNode handleMainMethodIfPresent(final List<MethodNode> methods) {
boolean found = false;
MethodNode result = null;
- for (Iterator<MethodNode> iter = methods.iterator(); iter.hasNext(); ) {
+ for (Iterator<MethodNode> iter = methods.iterator(); iter.hasNext();) {
MethodNode node = iter.next();
if (node.getName().equals("main")) {
if (node.isStatic() && node.getParameters().length == 1) {
@@ -508,4 +504,8 @@ public class ModuleNode extends ASTNode {
public BlockStatement getStatementBlock() {
return statementBlock;
}
+
+ public void setContext(SourceUnit sourceUnit) {
+ this.context = sourceUnit;
+ }
}