let cls mirror AST be gc-able

This commit is contained in:
peter
2016-10-18 11:07:05 +02:00
parent 44552eaf60
commit 9843716975
3 changed files with 29 additions and 13 deletions
@@ -21,11 +21,14 @@ import com.intellij.lang.Language;
import com.intellij.lang.java.JavaLanguage;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Key;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.TextRange;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.codeStyle.JavaCodeStyleSettingsFacade;
import com.intellij.psi.impl.PsiElementBase;
import com.intellij.psi.impl.smartPointers.AnchorTypeInfo;
import com.intellij.psi.impl.smartPointers.SelfElementInfo;
import com.intellij.psi.impl.source.SourceTreeToPsiMap;
import com.intellij.psi.impl.source.tree.TreeElement;
import com.intellij.psi.tree.IElementType;
@@ -44,7 +47,7 @@ public abstract class ClsElementImpl extends PsiElementBase implements PsiCompil
private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.compiled.ClsElementImpl");
private volatile PsiElement myMirror;
private volatile Pair<TextRange, AnchorTypeInfo> myMirror;
@Override
@NotNull
@@ -154,12 +157,9 @@ public abstract class ClsElementImpl extends PsiElementBase implements PsiCompil
@Override
public PsiElement getMirror() {
PsiElement mirror = myMirror;
if (mirror == null) {
((ClsFileImpl)getContainingFile()).getMirror();
mirror = myMirror;
}
return mirror;
PsiFile mirrorFile = ((ClsFileImpl)getContainingFile()).getMirror().getContainingFile();
Pair<TextRange, AnchorTypeInfo> mirror = myMirror;
return mirror == null ? null : SelfElementInfo.findElementInside(mirrorFile, mirror.first, mirror.second);
}
@Override
@@ -268,7 +268,7 @@ public abstract class ClsElementImpl extends PsiElementBase implements PsiCompil
PsiElement psi = element.getPsi();
psi.putUserData(COMPILED_ELEMENT, this);
myMirror = psi;
myMirror = Pair.create(element.getTextRange(), AnchorTypeInfo.obtainInfo(psi, JavaLanguage.INSTANCE));
}
protected static <T extends PsiElement> void setMirror(@Nullable T stub, @Nullable T mirror) throws InvalidMirrorException {
@@ -42,7 +42,6 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.*;
import com.intellij.psi.compiled.ClassFileDecompilers;
import com.intellij.psi.impl.CheckUtil;
import com.intellij.psi.impl.DebugUtil;
import com.intellij.psi.impl.JavaPsiImplementationHelper;
import com.intellij.psi.impl.PsiFileEx;
@@ -76,6 +75,7 @@ import org.jetbrains.org.objectweb.asm.ClassReader;
import org.jetbrains.org.objectweb.asm.Opcodes;
import java.io.IOException;
import java.lang.ref.Reference;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
@@ -99,7 +99,7 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub>
private final FileViewProvider myViewProvider;
private final boolean myIsForDecompiling;
private volatile SoftReference<StubTree> myStub;
private volatile TreeElement myMirrorFileElement;
private volatile Reference<TreeElement> myMirrorFileElement;
private volatile ClsPackageStatementImpl myPackageStatement;
private boolean myIsPhysical = true;
private boolean myInvalidated;
@@ -382,10 +382,10 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub>
@Override
public PsiElement getMirror() {
TreeElement mirrorTreeElement = myMirrorFileElement;
TreeElement mirrorTreeElement = SoftReference.dereference(myMirrorFileElement);
if (mirrorTreeElement == null) {
synchronized (myMirrorLock) {
mirrorTreeElement = myMirrorFileElement;
mirrorTreeElement = SoftReference.dereference(myMirrorFileElement);
if (mirrorTreeElement == null) {
VirtualFile file = getVirtualFile();
PsiClass[] classes = getClasses();
@@ -417,7 +417,7 @@ public class ClsFileImpl extends ClsRepositoryPsiElement<PsiClassHolderFileStub>
}
((PsiFileImpl)mirror).setOriginalFile(this);
myMirrorFileElement = mirrorTreeElement;
myMirrorFileElement = new SoftReference<TreeElement>(mirrorTreeElement);
}
}
}
@@ -22,12 +22,17 @@ import com.intellij.openapi.util.io.IoTestUtil;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.pom.java.LanguageLevel;
import com.intellij.psi.impl.compiled.ClsClassImpl;
import com.intellij.psi.impl.compiled.ClsElementImpl;
import com.intellij.psi.impl.compiled.ClsFileImpl;
import com.intellij.psi.impl.compiled.ClsParameterImpl;
import com.intellij.psi.impl.java.stubs.PsiMethodStub;
import com.intellij.psi.impl.source.tree.java.ClassElement;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.util.PsiUtil;
import com.intellij.testFramework.LeakHunter;
import com.intellij.testFramework.LightIdeaTestCase;
import com.intellij.util.GCUtil;
import com.intellij.util.ObjectUtils;
import com.intellij.util.indexing.FileBasedIndex;
@@ -436,4 +441,15 @@ public class ClsPsiTest extends LightIdeaTestCase {
assertTrue(String.valueOf(clsFile), clsFile instanceof ClsFileImpl);
return (PsiJavaFile)clsFile;
}
public void testClsPsiDoesNotHoldStrongReferencesToMirrorAST() {
PsiClass dbl = getJavaFacade().findClass(Double.class.getName(), myScope);
assertNotNull(dbl);
int hash1 = ((ClsClassImpl)dbl).getMirror().hashCode();
assertEquals(dbl, ((ClsClassImpl)dbl).getMirror().getUserData(ClsElementImpl.COMPILED_ELEMENT));
GCUtil.tryGcSoftlyReachableObjects();
LeakHunter.checkLeak(dbl, ClassElement.class, element -> element.getPsi().getUserData(ClsElementImpl.COMPILED_ELEMENT) == dbl);
assertFalse(hash1 == ((ClsClassImpl)dbl).getMirror().hashCode());
}
}