Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Parallel lock free testing, remove potential deadlocks, cache static data, go to descriptor via test #3752

Merged
merged 20 commits into from
Jun 26, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
84c9780
Implement fast parallel lock-free in-process testing for Java
KvanTTT Jun 21, 2022
e942e1a
Add final modifier to all static fields where it's possible
KvanTTT Jun 17, 2022
36b885c
Remove doubtful and not used static fields
KvanTTT Jun 17, 2022
4ccbb41
Fix potential deadlocks in Java runtime
KvanTTT Jun 17, 2022
dbce6b2
Unify C#, C++, Dart, Go, Python runtimes
KvanTTT Jun 19, 2022
8861ac4
Use AtomicInteger instead of int for static PredictionContext.globalN…
KvanTTT Jun 17, 2022
3c30268
Remove lock in Generator (now ANTLR tool is thread-safe)
KvanTTT Jun 17, 2022
7c5b3c2
Cache templates for codegen to static field, load only one time
KvanTTT Nov 26, 2021
f19cd67
Cache LeftRecursiveRules.stg to static field
KvanTTT Jun 18, 2022
6681a7a
Cache ANTLR error message templates to static field
KvanTTT Jun 18, 2022
93970f4
Cache runtime test templates to static field
KvanTTT Jun 18, 2022
1b9d77c
Clarify message of failed runtime tests
KvanTTT Jun 19, 2022
99fab5c
Pass testSourceUri to dynamicTest and to dynamicContainer for conveni…
KvanTTT Jun 20, 2022
8e6e1ed
Extract prepareGrammars method
KvanTTT Jun 20, 2022
2e8e3a8
Remove useless and outdated files
KvanTTT Jun 20, 2022
22cbf3c
Update pom.xml in runtime-testsuite
KvanTTT Jun 25, 2022
d287f1c
Use runtimePath instead of targetClassesPath for runtimes' sources
KvanTTT Jun 25, 2022
f235d33
Update doc
KvanTTT Jun 25, 2022
d40067d
Fix potential problems with concurrent access to hash maps
KvanTTT Jun 26, 2022
de255cc
Restore info about `mvn -Dtest=java.** test` in antlr-project-testing.md
KvanTTT Jun 26, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import org.antlr.v4.runtime.CharStream;
import org.antlr.v4.runtime.Lexer;

public abstract class RuntimeTestLexer extends Lexer {
protected java.io.PrintStream outStream = System.out;

public RuntimeTestLexer(CharStream input) { super(input); }

public void setOutStream(java.io.PrintStream outStream) { this.outStream = outStream; }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.TokenStream;

public abstract class RuntimeTestParser extends Parser {
protected java.io.PrintStream outStream = System.out;

public RuntimeTestParser(TokenStream input) {
super(input);
}

public void setOutStream(java.io.PrintStream outStream) {
parrt marked this conversation as resolved.
Show resolved Hide resolved
this.outStream = outStream;
}
}
Original file line number Diff line number Diff line change
@@ -1,20 +1,34 @@
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.tree.*;
import org.antlr.v4.runtime.atn.*;

import java.io.IOException;
import java.io.PrintStream;
import java.nio.file.Paths;
import java.util.Arrays;

public class Test {
public static void main(String[] args) throws Exception {
recognize(args[0], System.out, System.err);
}

public static void recognize(String inputFile, PrintStream outStream, PrintStream errorStream) throws IOException {
CustomStreamErrorListener errorListener = new CustomStreamErrorListener(errorStream);
<if(lexerName)>
CharStream input = CharStreams.fromPath(Paths.get(args[0]));
CharStream input = CharStreams.fromPath(Paths.get(inputFile));
<lexerName> lexer = new <lexerName>(input);
lexer.setOutStream(outStream);
lexer.removeErrorListeners();
lexer.addErrorListener(errorListener);
CommonTokenStream tokens = new CommonTokenStream(lexer);
<else>
CommonTokenStream tokens = null; // It's required for compilation
<endif>
<if(parserName)>
<parserName> parser = new <parserName>(tokens);
parser.setOutStream(outStream);
parser.removeErrorListeners();
parser.addErrorListener(errorListener);
<if(debug)>
parser.addErrorListener(new DiagnosticErrorListener());
<endif>
Expand All @@ -25,18 +39,36 @@ public class Test {
<endif>
ParserRuleContext tree = parser.<parserStartRuleName>();
<if(profile)>
System.out.println(Arrays.toString(profiler.getDecisionInfo()));
outStream.println(Arrays.toString(profiler.getDecisionInfo()));
<endif>
ParseTreeWalker.DEFAULT.walk(new TreeShapeListener(), tree);
<else>
tokens.fill();
for (Object t : tokens.getTokens()) System.out.println(t);
for (Object t : tokens.getTokens()) outStream.println(t);
<if(showDFA)>
System.out.print(lexer.getInterpreter().getDFA(Lexer.DEFAULT_MODE).toLexerString());
outStream.print(lexer.getInterpreter().getDFA(Lexer.DEFAULT_MODE).toLexerString());
<endif>
<endif>
}

static class CustomStreamErrorListener extends BaseErrorListener {
private final PrintStream printStream;

public CustomStreamErrorListener(PrintStream printStream){
this.printStream = printStream;
}

@Override
public void syntaxError(Recognizer\<?, ?> recognizer,
Object offendingSymbol,
int line,
int charPositionInLine,
String msg,
RecognitionException e) {
printStream.println("line " + line + ":" + charPositionInLine + " " + msg);
}
}

<if(parserName)>
static class TreeShapeListener implements ParseTreeListener {
@Override public void visitTerminal(TerminalNode node) { }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
writeln(s) ::= <<System.out.println(<s>);>>
write(s) ::= <<System.out.print(<s>);>>
writeList(s) ::= <<System.out.println(<s; separator="+">);>>
writeln(s) ::= <<outStream.println(<s>);>>
write(s) ::= <<outStream.print(<s>);>>
writeList(s) ::= <<outStream.println(<s; separator="+">);>>

False() ::= "false"

Expand Down Expand Up @@ -44,7 +44,7 @@ ModMemberEquals(n,m,v) ::= <%this.<n> % <m> == <v>%>

ModMemberNotEquals(n,m,v) ::= <%this.<n> % <m> != <v>%>

DumpDFA() ::= "this.dumpDFA();"
DumpDFA() ::= "this.dumpDFA(outStream);"

Pass() ::= ""

Expand Down Expand Up @@ -186,9 +186,9 @@ protected static class PositionAdjustingLexerATNSimulator extends LexerATNSimula

BasicListener(X) ::= <<
@parser::members {
public static class LeafListener extends TBaseListener {
public class LeafListener extends TBaseListener {
public void visitTerminal(TerminalNode node) {
System.out.println(node.getSymbol().getText());
outStream.println(node.getSymbol().getText());
}
}
}
Expand All @@ -214,27 +214,27 @@ public static class MyRuleNode extends ParserRuleContext {

TokenGetterListener(X) ::= <<
@parser::members {
public static class LeafListener extends TBaseListener {
public class LeafListener extends TBaseListener {
public void exitA(TParser.AContext ctx) {
if (ctx.getChildCount()==2)
System.out.printf("%s %s %s\n",ctx.INT(0).getSymbol().getText(),
outStream.printf("%s %s %s\n",ctx.INT(0).getSymbol().getText(),
ctx.INT(1).getSymbol().getText(),ctx.INT());
else
System.out.println(ctx.ID().getSymbol());
outStream.println(ctx.ID().getSymbol());
}
}
}
>>

RuleGetterListener(X) ::= <<
@parser::members {
public static class LeafListener extends TBaseListener {
public class LeafListener extends TBaseListener {
public void exitA(TParser.AContext ctx) {
if (ctx.getChildCount()==2) {
System.out.printf("%s %s %s\n",ctx.b(0).start.getText(),
outStream.printf("%s %s %s\n",ctx.b(0).start.getText(),
ctx.b(1).start.getText(),ctx.b().get(0).start.getText());
} else
System.out.println(ctx.b(0).start.getText());
outStream.println(ctx.b(0).start.getText());
}
}
}
Expand All @@ -243,26 +243,26 @@ public static class LeafListener extends TBaseListener {

LRListener(X) ::= <<
@parser::members {
public static class LeafListener extends TBaseListener {
public class LeafListener extends TBaseListener {
public void exitE(TParser.EContext ctx) {
if (ctx.getChildCount()==3) {
System.out.printf("%s %s %s\n",ctx.e(0).start.getText(),
outStream.printf("%s %s %s\n",ctx.e(0).start.getText(),
ctx.e(1).start.getText(), ctx.e().get(0).start.getText());
} else
System.out.println(ctx.INT().getSymbol().getText());
outStream.println(ctx.INT().getSymbol().getText());
}
}
}
>>

LRWithLabelsListener(X) ::= <<
@parser::members {
public static class LeafListener extends TBaseListener {
public class LeafListener extends TBaseListener {
public void exitCall(TParser.CallContext ctx) {
System.out.printf("%s %s\n",ctx.e().start.getText(),ctx.eList());
outStream.printf("%s %s\n",ctx.e().start.getText(),ctx.eList());
}
public void exitInt(TParser.IntContext ctx) {
System.out.println(ctx.INT().getSymbol().getText());
outStream.println(ctx.INT().getSymbol().getText());
}
}
}
Expand All @@ -277,13 +277,13 @@ void foo() {
>>

Declare_foo() ::= <<
public void foo() {System.out.println("foo");}
public void foo() {outStream.println("foo");}
>>

Invoke_foo() ::= "foo();"

Declare_pred() ::= <<boolean pred(boolean v) {
System.out.println("eval="+v);
outStream.println("eval="+v);
return v;
}
>>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import java.util.*;

public class CustomDescriptors {
public static HashMap<String, RuntimeTestDescriptor[]> descriptors;
public final static HashMap<String, RuntimeTestDescriptor[]> descriptors;

static {
descriptors = new HashMap<>();
Expand Down
13 changes: 13 additions & 0 deletions runtime-testsuite/test/org/antlr/v4/test/runtime/FileUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.antlr.v4.runtime.misc.Utils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.EnumSet;
Expand Down Expand Up @@ -60,6 +61,18 @@ public static boolean moveFile(File sourceFir, String destDir, String fileName)
return file.renameTo(newFile);
}

public static void replaceInFile(Path sourcePath, String target, String replacement) throws IOException {
replaceInFile(sourcePath, sourcePath, target, replacement);
}

public static void replaceInFile(Path sourcePath, Path destPath, String target, String replacement) throws IOException {
String content = new String(Files.readAllBytes(sourcePath), StandardCharsets.UTF_8);
parrt marked this conversation as resolved.
Show resolved Hide resolved
String newContent = content.replace(target, replacement);
try (PrintWriter out = new PrintWriter(destPath.toString())) {
out.println(newContent);
}
}

public static void mkdir(String dir) {
File f = new File(dir);
f.mkdirs();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package org.antlr.v4.test.runtime;

public class GeneratedFile {
public final String name;
public final boolean isParser;

public GeneratedFile(String name, boolean isParser) {
this.name = name;
this.isParser = isParser;
}

@Override
public String toString() {
return name + "; isParser:" + isParser;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@
import static org.antlr.v4.test.runtime.FileUtils.writeFile;

public class Generator {
/** ANTLR isn't thread-safe to process grammars so we use a global lock for testing */
public static final Object antlrLock = new Object();

/** Write a grammar to tmpdir and run antlr */
public static ErrorQueue antlrOnString(String workdir,
String targetName,
Expand Down Expand Up @@ -69,9 +66,7 @@ public static ErrorQueue antlrOnString(String workdir,
if (defaultListener) {
antlr.addListener(new DefaultToolListener(antlr));
}
synchronized (antlrLock) {
antlr.processGrammarsOnCommandLine();
}
antlr.processGrammarsOnCommandLine();

List<String> errors = new ArrayList<>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,13 @@ public class RunOptions {
public final boolean showDFA;
public final Stage endStage;
public final boolean returnObject;
public final String superClass;

public RunOptions(String grammarFileName, String grammarStr, String parserName, String lexerName,
boolean useListener, boolean useVisitor, String startRuleName,
String input, boolean profile, boolean showDiagnosticErrors,
boolean showDFA, Stage endStage, boolean returnObject,
String language) {
String language, String superClass) {
this.grammarFileName = grammarFileName;
this.grammarStr = grammarStr;
this.parserName = parserName;
Expand Down Expand Up @@ -63,5 +64,6 @@ else if (lexerName != null) {
this.showDFA = showDFA;
this.endStage = endStage;
this.returnObject = returnObject;
this.superClass = superClass;
}
}
28 changes: 17 additions & 11 deletions runtime-testsuite/test/org/antlr/v4/test/runtime/RuntimeRunner.java
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,17 @@ public static String getRuntimePath(String language) {
}

public State run(RunOptions runOptions) {
String[] options = runOptions.useVisitor ? new String[]{"-visitor"} : new String[0];
List<String> options = new ArrayList<>();
if (runOptions.useVisitor) {
options.add("-visitor");
}
if (runOptions.superClass != null && runOptions.superClass.length() > 0) {
options.add("-DsuperClass=" + runOptions.superClass);
}
ErrorQueue errorQueue = Generator.antlrOnString(getTempDirPath(), getLanguage(),
runOptions.grammarFileName, runOptions.grammarStr, false, options);
runOptions.grammarFileName, runOptions.grammarStr, false, options.toArray(new String[0]));

List<String> generatedFiles = getGeneratedFiles(runOptions);
List<GeneratedFile> generatedFiles = getGeneratedFiles(runOptions);
GeneratedState generatedState = new GeneratedState(errorQueue, generatedFiles, null);

if (generatedState.containsErrors() || runOptions.endStage == Stage.Generate) {
Expand All @@ -152,28 +158,28 @@ public State run(RunOptions runOptions) {
return executedState;
}

protected List<String> getGeneratedFiles(RunOptions runOptions) {
List<String> files = new ArrayList<>();
protected List<GeneratedFile> getGeneratedFiles(RunOptions runOptions) {
List<GeneratedFile> files = new ArrayList<>();
String extensionWithDot = "." + getExtension();
String fileGrammarName = grammarNameToFileName(runOptions.grammarName);
boolean isCombinedGrammarOrGo = runOptions.lexerName != null && runOptions.parserName != null || getLanguage().equals("Go");
if (runOptions.lexerName != null) {
files.add(fileGrammarName + (isCombinedGrammarOrGo ? getLexerSuffix() : "") + extensionWithDot);
files.add(new GeneratedFile(fileGrammarName + (isCombinedGrammarOrGo ? getLexerSuffix() : "") + extensionWithDot, false));
}
if (runOptions.parserName != null) {
files.add(fileGrammarName + (isCombinedGrammarOrGo ? getParserSuffix() : "") + extensionWithDot);
files.add(new GeneratedFile(fileGrammarName + (isCombinedGrammarOrGo ? getParserSuffix() : "") + extensionWithDot, true));
if (runOptions.useListener) {
files.add(fileGrammarName + getListenerSuffix() + extensionWithDot);
files.add(new GeneratedFile(fileGrammarName + getListenerSuffix() + extensionWithDot, true));
String baseListenerSuffix = getBaseListenerSuffix();
if (baseListenerSuffix != null) {
files.add(fileGrammarName + baseListenerSuffix + extensionWithDot);
files.add(new GeneratedFile(fileGrammarName + baseListenerSuffix + extensionWithDot, true));
}
}
if (runOptions.useVisitor) {
files.add(fileGrammarName + getVisitorSuffix() + extensionWithDot);
files.add(new GeneratedFile(fileGrammarName + getVisitorSuffix() + extensionWithDot, true));
String baseVisitorSuffix = getBaseVisitorSuffix();
if (baseVisitorSuffix != null) {
files.add(fileGrammarName + baseVisitorSuffix + extensionWithDot);
files.add(new GeneratedFile(fileGrammarName + baseVisitorSuffix + extensionWithDot, true));
}
}
}
Expand Down
Loading