From 98437169757106b21620c13b451e07c7fd40d1db Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 18 Oct 2016 10:13:31 +0200 Subject: [PATCH] let cls mirror AST be gc-able --- .../psi/impl/compiled/ClsElementImpl.java | 16 ++++++++-------- .../intellij/psi/impl/compiled/ClsFileImpl.java | 10 +++++----- .../testSrc/com/intellij/psi/ClsPsiTest.java | 16 ++++++++++++++++ 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsElementImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsElementImpl.java index 4d597e1ca206..b9a511698371 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsElementImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsElementImpl.java @@ -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 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 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 void setMirror(@Nullable T stub, @Nullable T mirror) throws InvalidMirrorException { diff --git a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java index 3e7476ac6551..d938d7a2743a 100644 --- a/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java +++ b/java/java-psi-impl/src/com/intellij/psi/impl/compiled/ClsFileImpl.java @@ -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 private final FileViewProvider myViewProvider; private final boolean myIsForDecompiling; private volatile SoftReference myStub; - private volatile TreeElement myMirrorFileElement; + private volatile Reference myMirrorFileElement; private volatile ClsPackageStatementImpl myPackageStatement; private boolean myIsPhysical = true; private boolean myInvalidated; @@ -382,10 +382,10 @@ public class ClsFileImpl extends ClsRepositoryPsiElement @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 } ((PsiFileImpl)mirror).setOriginalFile(this); - myMirrorFileElement = mirrorTreeElement; + myMirrorFileElement = new SoftReference(mirrorTreeElement); } } } diff --git a/java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java b/java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java index 32b21fa4ad7b..5907f03ef1a7 100644 --- a/java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java +++ b/java/java-tests/testSrc/com/intellij/psi/ClsPsiTest.java @@ -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()); + } } \ No newline at end of file