diff --git a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java index 3112ca401d2e..98e0fb1410f6 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/PsiDocumentManagerImpl.java @@ -38,7 +38,10 @@ import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.progress.ProgressManager; import com.intellij.openapi.project.Project; import com.intellij.openapi.project.ProjectLocator; -import com.intellij.openapi.util.*; +import com.intellij.openapi.util.Computable; +import com.intellij.openapi.util.Key; +import com.intellij.openapi.util.Ref; +import com.intellij.openapi.util.UserDataHolderEx; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.psi.*; import com.intellij.psi.impl.smartPointers.SmartPointerManagerImpl; @@ -104,12 +107,12 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec ApplicationManager.getApplication().addApplicationListener(new ApplicationAdapter() { @Override public void beforeWriteActionStart(Object action) { - documentCommitThread.disable(action); + documentCommitThread.disable("Write action started: "+ action); } @Override public void writeActionFinished(Object action) { - documentCommitThread.enable(action); + documentCommitThread.enable("Write action finished: "+action); } }, myProject); documentCommitThread.enable("project open"); @@ -336,13 +339,15 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec } } finally { + //myDocumentCommitThread.log("in PDI.finishDoc: ",document, synchronously, success, myUncommittedDocuments); if (success) { myUncommittedDocuments.remove(document); - + //myDocumentCommitThread.log("in PDI.finishDoc: removed doc",document, synchronously, success, myUncommittedDocuments); ((DocumentImpl)document).normalizeRangeMarkers(); InjectedLanguageUtil.commitAllInjectedDocuments(document, myProject); } myIsCommitInProgress = false; + //myDocumentCommitThread.log("in PDI.finishDoc: exit",document, synchronously, success, myUncommittedDocuments); } if (success) { @@ -559,7 +564,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec if (file == null) continue; if (file.isPhysical() && mySmartPointerManager != null) { // mock tests - SmartPointerManagerImpl.fastenBelts(file, event.getOffset(), null); + mySmartPointerManager.fastenBelts(file, event.getOffset(), null); } final TextBlock textBlock = getTextBlock(file); @@ -598,7 +603,7 @@ public class PsiDocumentManagerImpl extends PsiDocumentManager implements Projec for (PsiFile file : files) { if (file == null || file instanceof PsiFileImpl && ((PsiFileImpl)file).getTreeElement() == null) continue; if (mySmartPointerManager != null) { // mock tests - SmartPointerManagerImpl.unfastenBelts(file, event.getOffset()); + mySmartPointerManager.unfastenBelts(file, event.getOffset()); } final TextBlock textBlock = getTextBlock(file); if (textBlock.isLocked()) continue; diff --git a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java index a7ddca1951d6..a1fb032c7a78 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/file/impl/FileManagerImpl.java @@ -872,7 +872,7 @@ public class FileManagerImpl implements FileManager { } if (oldPsiFile != null && oldPsiFile.isPhysical()) { - SmartPointerManagerImpl.fastenBelts(oldPsiFile, 0, null); + ((SmartPointerManagerImpl)SmartPointerManager.getInstance(myManager.getProject())).fastenBelts(oldPsiFile, 0, null); } ApplicationManager.getApplication().runWriteAction( new ExternalChangeAction() { diff --git a/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java b/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java index 965acf5cbeff..f36929792328 100644 --- a/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java +++ b/platform/lang-impl/src/com/intellij/psi/impl/smartPointers/SmartPointerManagerImpl.java @@ -30,19 +30,18 @@ import com.intellij.openapi.util.TextRange; import com.intellij.psi.*; import com.intellij.psi.impl.source.tree.injected.InjectedLanguageUtil; import com.intellij.reference.SoftReference; +import com.intellij.util.containers.UnsafeWeakList; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.lang.ref.Reference; -import java.lang.ref.WeakReference; -import java.util.ArrayList; import java.util.List; import java.util.Set; public class SmartPointerManagerImpl extends SmartPointerManager { private static final Logger LOG = Logger.getInstance("#com.intellij.psi.impl.smartPointers.SmartPointerManagerImpl"); - private static final Key>> SMART_POINTERS_IN_PSI_FILE_KEY = Key.create("SMART_POINTERS_IN_DOCUMENT_KEY"); + private static final Key> SMART_POINTERS_IN_PSI_FILE_KEY = Key.create("SMART_POINTERS_IN_DOCUMENT_KEY"); private static final Key BELTS_ARE_FASTEN_KEY = Key.create("BELTS_ARE_FASTEN_KEY"); private final Project myProject; @@ -51,13 +50,13 @@ public class SmartPointerManagerImpl extends SmartPointerManager { myProject = project; } - public static void fastenBelts(@NotNull PsiFile file, int offset, @Nullable RangeMarker cachedRangeMarker) { + public void fastenBelts(@NotNull PsiFile file, int offset, @Nullable RangeMarker cachedRangeMarker) { synchronized (file) { if (areBeltsFastened(file)) return; file.putUserData(BELTS_ARE_FASTEN_KEY, Boolean.TRUE); - List> pointers = getPointers(file); + List pointers = getPointers(file); if (pointers == null) return; PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(file.getProject()); Document document = psiDocumentManager.getDocument(file); @@ -65,13 +64,9 @@ public class SmartPointerManagerImpl extends SmartPointerManager { ((DocumentImpl)document).normalizeRangeMarkers(); } - int index = 0; - for (int i = 0; i < pointers.size(); i++) { - WeakReference reference = pointers.get(i); - SmartPointerEx pointer = reference.get(); + for (SmartPointerEx pointer : pointers) { if (pointer != null) { pointer.fastenBelt(offset, cachedRangeMarker); - pointers.set(index++, reference); } } @@ -81,15 +76,10 @@ public class SmartPointerManagerImpl extends SmartPointerManager { RangeMarker cachedMarker = getCachedRangeMarkerToInjectedFragment(injectedFile); fastenBelts(injectedFile, 0, cachedMarker); } - - int size = pointers.size(); - for (int i = size - 1; i >= index; i--) { - pointers.remove(i); - } } } - private static RangeMarker getCachedRangeMarkerToInjectedFragment(PsiFile injectedFile) { + private static RangeMarker getCachedRangeMarkerToInjectedFragment(@NotNull PsiFile injectedFile) { PsiElement hostContext = injectedFile.getContext(); RangeMarker cachedMarker = null; if (hostContext != null) { @@ -102,12 +92,12 @@ public class SmartPointerManagerImpl extends SmartPointerManager { return cachedMarker; } - public static void unfastenBelts(@NotNull PsiFile file, int offset) { + public void unfastenBelts(@NotNull PsiFile file, int offset) { synchronized (file) { PsiDocumentManager psiDocumentManager = PsiDocumentManager.getInstance(file.getProject()); file.putUserData(BELTS_ARE_FASTEN_KEY, null); - List> pointers = getPointers(file); + List pointers = getPointers(file); if (pointers == null) return; Document document = psiDocumentManager.getDocument(file); @@ -115,13 +105,9 @@ public class SmartPointerManagerImpl extends SmartPointerManager { ((DocumentImpl)document).normalizeRangeMarkers(); } - int index = 0; - for (int i = 0; i < pointers.size(); i++) { - WeakReference reference = pointers.get(i); - SmartPointerEx pointer = reference.get(); + for (SmartPointerEx pointer : pointers) { if (pointer != null) { pointer.unfastenBelt(offset); - pointers.set(index++, reference); } } @@ -130,15 +116,10 @@ public class SmartPointerManagerImpl extends SmartPointerManager { if (injectedFile == null) continue; unfastenBelts(injectedFile, 0); } - - int size = pointers.size(); - for (int i = size - 1; i >= index; i--) { - pointers.remove(i); - } } } - public static void synchronizePointers(PsiFile file) { + public static void synchronizePointers(@NotNull PsiFile file) { final Set languages = file.getViewProvider().getLanguages(); for (Language language : languages) { final PsiFile f = file.getViewProvider().getPsi(language); @@ -148,17 +129,13 @@ public class SmartPointerManagerImpl extends SmartPointerManager { } } - private static void _synchronizePointers(final PsiFile file) { - List> pointers = getPointers(file); + private static void _synchronizePointers(@NotNull PsiFile file) { + List pointers = getPointers(file); if (pointers == null) return; - int index = 0; - for (int i = 0; i < pointers.size(); i++) { - WeakReference reference = pointers.get(i); - SmartPointerEx pointer = reference.get(); + for (SmartPointerEx pointer : pointers) { if (pointer != null) { pointer.documentAndPsiInSync(); - pointers.set(index++, reference); } } @@ -168,11 +145,6 @@ public class SmartPointerManagerImpl extends SmartPointerManager { if (injectedfile == null) continue; _synchronizePointers(injectedfile); } - - int size = pointers.size(); - for (int i = size - 1; i >= index; i--) { - pointers.remove(i); - } } private static final Key> CACHED_SMART_POINTER_KEY = Key.create("CACHED_SMART_POINTER_KEY"); @@ -197,7 +169,7 @@ public class SmartPointerManagerImpl extends SmartPointerManager { return pointer; } - private static SmartPsiElementPointer getCachedPointer(E element) { + private static SmartPsiElementPointer getCachedPointer(@NotNull E element) { Reference data = element.getUserData(CACHED_SMART_POINTER_KEY); return data == null ? null : data.get(); } @@ -214,26 +186,15 @@ public class SmartPointerManagerImpl extends SmartPointerManager { return pointer; } - private static void initPointer(SmartPointerEx pointer, PsiFile containingFile) { + private static void initPointer(@NotNull SmartPointerEx pointer, PsiFile containingFile) { if (containingFile == null) return; synchronized (containingFile) { - //Document document = PsiDocumentManager.getInstance(myProject).getCachedDocument(containingFile); - //todo - //if (document != null) { - // //[ven] this is a really NASTY hack; when no smart pointer is kept on UsageInfo then remove this conditional - // if (!(element instanceof PsiFile)) { - // PsiDocumentManagerImpl documentManager = (PsiDocumentManagerImpl)PsiDocumentManager.getInstance(myProject); - // LOG.assertTrue(!documentManager.isUncommited(document) || documentManager.isCommittingDocument(document), "Document for : " + - // containingFile + " is not committed"); - // } - //} - - List> pointers = getPointers(containingFile); + List pointers = getPointers(containingFile); if (pointers == null) { - pointers = new ArrayList>(); + pointers = new UnsafeWeakList(); // we synchronise access anyway by containingFile containingFile.putUserData(SMART_POINTERS_IN_PSI_FILE_KEY, pointers); } - pointers.add(new WeakReference(pointer)); + pointers.add(pointer); if (areBeltsFastened(containingFile)) { pointer.fastenBelt(0, null); @@ -241,11 +202,11 @@ public class SmartPointerManagerImpl extends SmartPointerManager { } } - private static List> getPointers(@NotNull PsiFile containingFile) { + private static List getPointers(@NotNull PsiFile containingFile) { return containingFile.getUserData(SMART_POINTERS_IN_PSI_FILE_KEY); } - private static boolean areBeltsFastened(final PsiFile file) { + private static boolean areBeltsFastened(@NotNull PsiFile file) { return file.getUserData(BELTS_ARE_FASTEN_KEY) == Boolean.TRUE; } diff --git a/platform/util/src/com/intellij/util/containers/UnsafeWeakList.java b/platform/util/src/com/intellij/util/containers/UnsafeWeakList.java new file mode 100644 index 000000000000..57d8ed8fc2a9 --- /dev/null +++ b/platform/util/src/com/intellij/util/containers/UnsafeWeakList.java @@ -0,0 +1,168 @@ +/* + * Copyright 2000-2011 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.intellij.util.containers; + +import com.intellij.openapi.diagnostic.Logger; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +/** + * Implementation of the {@link java.util.List} interface which: + *
    + *
  • Stores elements using weak semantics (see {@link java.lang.ref.WeakReference})
  • + *
  • Automatically reclaims storage for garbage collected elements
  • + *
  • Is NOT thread safe
  • + *
+ */ +public class UnsafeWeakList extends AbstractList { + private static final Logger LOG = Logger.getInstance("#com.intellij.util.containers.UnsafeWeakList"); + protected final WeakReferenceArray myArray; + + public UnsafeWeakList() { + this(new WeakReferenceArray()); + } + + // For testing only + UnsafeWeakList(@NotNull WeakReferenceArray array) { + myArray = array; + } + + public T get(int index) { + return myArray.get(index); + } + + public boolean add(T element) { + tryReduceCapacity(-1); + myArray.add(element); + return true; + } + + @Override + public boolean contains(Object o) { + return super.contains(o); + } + + public boolean addIfAbsent(T element) { + tryReduceCapacity(-1); + if (contains(element)) return false; + myArray.add(element); + return true; + } + + public void add(int index, T element) { + tryReduceCapacity(-1); + myArray.add(index, element); + } + + public T remove(int index) { + tryReduceCapacity(-1); + return myArray.remove(index); + } + + public Iterator iterator() { + return new MyIterator(); + } + + public int size() { + return myArray.size(); + } + + public List toStrongList() { + List result = new ArrayList(myArray.size()); + myArray.toStrongCollection(result); + return result; + } + + private int tryReduceCapacity(int trackIndex) { + modCount++; + if (canReduceCapacity()) { + return myArray.reduceCapacity(trackIndex); + } + else { + return probablyCompress(trackIndex); + } + } + + private int myCompressCountdown = 10; + private int probablyCompress(int trackIndex) { + myCompressCountdown--; + if (myCompressCountdown > 0) return trackIndex; + int newIndex = myArray.compress(trackIndex); + myCompressCountdown = myArray.size() + 10; + return newIndex; + } + + private boolean canReduceCapacity() { + return WeakReferenceArray.MINIMUM_CAPACITY * 2 < myArray.getCapacity() && + myArray.getCapacity() > myArray.getAliveCount() * 3; + } + + protected class MyIterator implements Iterator { + private int myNextIndex = -1; + private int myCurrentIndex = -1; + private T myNextElement = null; + private int myModCount = modCount; + + public MyIterator() { + findNext(); + } + + protected void findNext() { + myNextElement = null; + while (myNextElement == null) { + myNextIndex = myArray.nextValid(myNextIndex); + if (myNextIndex >= myArray.size()) { + myNextIndex = -1; + myNextElement = null; + return; + } + myNextElement = myArray.get(myNextIndex); + } + } + + public boolean hasNext() { + return myNextElement != null; + } + + public T next() { + if (modCount != myModCount) throw new ConcurrentModificationException(); + if (myNextElement == null) throw new NoSuchElementException(); + T element = myNextElement; + myCurrentIndex = myNextIndex; + findNext(); + return element; + } + + public void remove() { + if (myCurrentIndex == -1) throw new IllegalStateException(); + myArray.remove(myCurrentIndex); + final int removedIndex = myCurrentIndex; + int newIndex = tryReduceCapacity(myNextIndex); + myCurrentIndex = -1; + myModCount = modCount; + if (!hasNext()) return; + if (newIndex < 0) { + LOG.error(" was: " + myNextIndex + + " got: " + newIndex + + " size: " + myArray.size() + + " current: " + removedIndex); + } + myNextIndex = newIndex; + LOG.assertTrue(myArray.get(myNextIndex) == myNextElement); + } + } +} diff --git a/platform/util/src/com/intellij/util/containers/WeakList.java b/platform/util/src/com/intellij/util/containers/WeakList.java index 3bb72781c520..7fb01f556302 100644 --- a/platform/util/src/com/intellij/util/containers/WeakList.java +++ b/platform/util/src/com/intellij/util/containers/WeakList.java @@ -15,35 +15,41 @@ */ package com.intellij.util.containers; -import com.intellij.openapi.diagnostic.Logger; +import org.jetbrains.annotations.NotNull; -import java.util.*; - -public class WeakList extends AbstractList { - private static final Logger LOG = Logger.getInstance("#com.intellij.util.containers.WeakList"); - private final WeakReferenceArray myArray; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +/** + * Implementation of the {@link List} interface which: + *
    + *
  • Stores elements using weak semantics (see {@link java.lang.ref.WeakReference})
  • + *
  • Automatically reclaims storage for garbage collected elements
  • + *
  • Is thread safe
  • + *
+ */ +public class WeakList extends UnsafeWeakList { public WeakList() { this(new WeakReferenceArray()); } // For testing only - WeakList(WeakReferenceArray array) { - myArray = array; + WeakList(@NotNull WeakReferenceArray array) { + super(array); } public T get(int index) { synchronized (myArray) { - return myArray.get(index); + return super.get(index); } } public boolean add(T element) { synchronized (myArray) { - tryReduceCapacity(-1); - myArray.add(element); + return super.add(element); } - return true; } @Override @@ -55,24 +61,19 @@ public class WeakList extends AbstractList { public boolean addIfAbsent(T element) { synchronized (myArray) { - tryReduceCapacity(-1); - if (contains(element)) return false; - myArray.add(element); + return super.addIfAbsent(element); } - return true; } public void add(int index, T element) { synchronized (myArray) { - tryReduceCapacity(-1); - myArray.add(index, element); + super.add(index, element); } } public T remove(int index) { synchronized (myArray) { - tryReduceCapacity(-1); - return myArray.remove(index); + return super.remove(index); } } @@ -84,7 +85,7 @@ public class WeakList extends AbstractList { } public Iterator iterator() { - return new MyIterator(); + return new MySyncIterator(); } public int size() { @@ -101,85 +102,16 @@ public class WeakList extends AbstractList { } } - private int tryReduceCapacity(int trackIndex) { - modCount++; - if (canReduceCapacity()) { - return myArray.reduceCapacity(trackIndex); - } - else { - return propablyCompress(trackIndex); - } - } - - private int myCompressCountdown = 10; - private int propablyCompress(int trackIndex) { - myCompressCountdown--; - if (myCompressCountdown > 0) return trackIndex; - int newIndex = myArray.compress(trackIndex); - myCompressCountdown = myArray.size() + 10; - return newIndex; - } - - private boolean canReduceCapacity() { - return WeakReferenceArray.MINIMUM_CAPACITY*2 < myArray.getCapacity() && - myArray.getCapacity() > myArray.getAliveCount()*3; - } - - private class MyIterator implements Iterator { - private int myNextIndex = -1; - private int myCurrentIndex = -1; - private T myNextElement = null; - private int myModCount = modCount; - - public MyIterator() { - findNext(); - } - - private void findNext() { + private class MySyncIterator extends MyIterator { + protected void findNext() { synchronized (myArray) { - myNextElement = null; - while (myNextElement == null) { - myNextIndex = myArray.nextValid(myNextIndex); - if (myNextIndex >= myArray.size()) { - myNextIndex = -1; - myNextElement = null; - return; - } - myNextElement = myArray.get(myNextIndex); - } + super.findNext(); } } - public boolean hasNext() { - return myNextElement != null; - } - - public T next() { - if (modCount != myModCount) throw new ConcurrentModificationException(); - if (myNextElement == null) throw new NoSuchElementException(); - T element = myNextElement; - myCurrentIndex = myNextIndex; - findNext(); - return element; - } - public void remove() { synchronized (myArray) { - if (myCurrentIndex == -1) throw new IllegalStateException(); - myArray.remove(myCurrentIndex); - final int removedIndex = myCurrentIndex; - int newIndex = tryReduceCapacity(myNextIndex); - myCurrentIndex = -1; - myModCount = modCount; - if (!hasNext()) return; - if (newIndex < 0) { - LOG.error(" was: " + myNextIndex + - " got: " + newIndex + - " size: " + myArray.size() + - " current: " + removedIndex); - } - myNextIndex = newIndex; - LOG.assertTrue(myArray.get(myNextIndex) == myNextElement); + super.remove(); } } }