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.

#2691
  • Loading branch information
EcljpseB0T authored and jukzi committed Oct 7, 2024
1 parent d9fa3af commit 55d99cd
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,20 @@
*******************************************************************************/
package org.eclipse.jdt.internal.compiler;

import java.lang.ref.SoftReference;
import java.util.*;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData;
import org.eclipse.jdt.internal.compiler.util.Util;

/**
* A compilation result consists of all information returned by the compiler for
* a single compiled compilation source unit. This includes:
Expand All @@ -34,19 +48,6 @@
* specific fields and methods which were referenced, but does contain their
* declaring types and any other types used to locate such fields or methods.
*/
import java.util.*;
import org.eclipse.jdt.core.compiler.CategorizedProblem;
import org.eclipse.jdt.core.compiler.CharOperation;
import org.eclipse.jdt.core.compiler.IProblem;
import org.eclipse.jdt.internal.compiler.ast.AbstractMethodDeclaration;
import org.eclipse.jdt.internal.compiler.env.ICompilationUnit;
import org.eclipse.jdt.internal.compiler.impl.ReferenceContext;
import org.eclipse.jdt.internal.compiler.lookup.AnnotationBinding;
import org.eclipse.jdt.internal.compiler.lookup.SourceTypeBinding;
import org.eclipse.jdt.internal.compiler.lookup.TypeConstants;
import org.eclipse.jdt.internal.compiler.parser.RecoveryScannerData;
import org.eclipse.jdt.internal.compiler.util.Util;

@SuppressWarnings({ "rawtypes", "unchecked" })
public class CompilationResult {

Expand Down Expand Up @@ -77,6 +78,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 @@ -481,4 +484,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 @@ -891,6 +891,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 @@ -176,6 +176,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 @@ -11604,7 +11604,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 @@ -12841,6 +12841,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 55d99cd

Please sign in to comment.