Skip to content

Commit

Permalink
[performance] Avoid reading SourceFile twice
Browse files Browse the repository at this point in the history
During compile parsing happens in two stages:
1. diet parse (any blocks like method bodies are skipped)
2. parse bodies
Both phases did read the source .java file from file system. With this
change the file contents is kept in CompilationResult.contentRef until
no longer needed. It is cached in
a SoftReference to avoid OutOfMemoryError.

eclipse-jdt#2691
  • Loading branch information
EcljpseB0T committed Sep 30, 2024
1 parent 7cd2e50 commit 6468536
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
*******************************************************************************/
package org.eclipse.jdt.internal.compiler;

import java.lang.ref.SoftReference;
import java.util.ArrayList;
/**
* A compilation result consists of all information returned by the compiler for
Expand Down Expand Up @@ -87,6 +88,8 @@ public class CompilationResult {
private boolean hasMandatoryErrors;
public List<AnnotationBinding[]> annotations = new ArrayList<>(1);
private List<Runnable> scheduledProblems;
private volatile boolean cacheSource;
private volatile SoftReference<char[]> contentRef;

private static final int[] EMPTY_LINE_ENDS = Util.EMPTY_INT_ARRAY;
private static final Comparator PROBLEM_COMPARATOR = new Comparator() {
Expand Down Expand Up @@ -491,4 +494,29 @@ public void materializeProblems() {
}
}
}

public void cacheSource() {
this.cacheSource = true;
}

public char[] getContents() {
SoftReference<char[]> cr = this.contentRef;
if (cr != null) {
char[] cachedContents = cr.get();
if (cachedContents != null) {
return cachedContents;
}
}
return this.compilationUnit.getContents();
}

public void cacheContents(char[] contents) {
if (this.cacheSource) {
this.contentRef = new SoftReference<>(contents);
}
}

public void releaseContent() {
this.contentRef = null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -869,6 +869,7 @@ protected void internalBeginToCompile(ICompilationUnit[] sourceUnits, int maxUni
if (this.totalUnits < this.parseThreshold) {
parsedUnit = this.parser.parse(sourceUnits[i], unitResult);
} else {
unitResult.cacheSource();
parsedUnit = this.parser.dietParse(sourceUnits[i], unitResult);
}
long resolveStart = System.currentTimeMillis();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,7 @@ public void cleanUp() {

if (this.scope != null)
this.scope.cleanUpInferenceContexts();
this.compilationResult.releaseContent();
}

private void cleanUp(TypeDeclaration type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11615,7 +11615,7 @@ public void getMethodBodies(CompilationUnitDeclaration unit) {
CompilationResult compilationResult = unit.compilationResult;
char[] contents = this.readManager != null
? this.readManager.getContents(compilationResult.compilationUnit)
: compilationResult.compilationUnit.getContents();
: compilationResult.getContents();
this.scanner.setSource(contents, compilationResult);

if (this.javadocParser != null && this.javadocParser.checkDocComment) {
Expand Down Expand Up @@ -12852,6 +12852,7 @@ public CompilationUnitDeclaration parse(
problemReporter().cannotReadSource(this.compilationUnit, abortException, this.options.verbose);
contents = CharOperation.NO_CHAR; // pretend empty from thereon
}
compilationResult.cacheContents(contents);
this.scanner.setSource(contents);
this.compilationUnit.sourceEnd = this.scanner.source.length - 1;
if (end != -1) this.scanner.resetTo(start, end);
Expand Down

0 comments on commit 6468536

Please sign in to comment.