interval trees: speed up iteration by making Getter.get hot spot bimorphic instead of megamorphic

GitOrigin-RevId: 5cf5fbd4919e23feef807ed457af9d723e6203c4
This commit is contained in:
Peter Gromov
2020-06-12 15:29:30 +03:00
committed by intellij-monorepo-bot
parent e9771b8129
commit eaefb91446
13 changed files with 38 additions and 99 deletions
@@ -7,6 +7,7 @@ import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.ex.MarkupIterator;
import com.intellij.openapi.editor.ex.RangeMarkerEx;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.StaticGetter;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Processor;
import com.intellij.util.SmartList;
@@ -164,8 +165,8 @@ abstract class IntervalTreeImpl<T> extends RedBlackTree<T> implements IntervalTr
}
}
protected Getter<E> createGetter(@NotNull E interval) {
return new WeakReferencedGetter<>(interval, myIntervalTree.myReferenceQueue);
private Getter<E> createGetter(@NotNull E interval) {
return myIntervalTree.keepIntervalsOnWeakReferences() ? new WeakReferencedGetter<>(interval, myIntervalTree.myReferenceQueue) : new StaticGetter<>(interval);
}
private static class WeakReferencedGetter<T> extends WeakReference<T> implements Getter<T> {
@@ -393,6 +394,10 @@ abstract class IntervalTreeImpl<T> extends RedBlackTree<T> implements IntervalTr
}
}
protected boolean keepIntervalsOnWeakReferences() {
return true;
}
@NotNull
protected abstract IntervalNode<T> createNewNode(@NotNull T key, int start, int end,
boolean greedyToLeft, boolean greedyToRight, boolean stickingToRight, int layer);
@@ -12,7 +12,6 @@ import com.intellij.openapi.editor.ex.MarkupModelEx;
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
import com.intellij.openapi.editor.markup.*;
import com.intellij.openapi.util.Comparing;
import com.intellij.openapi.util.Getter;
import com.intellij.openapi.util.Key;
import com.intellij.util.BitUtil;
import com.intellij.util.Consumer;
@@ -27,7 +26,7 @@ import java.awt.*;
* Implementation of the markup element for the editor and document.
* @author max
*/
class RangeHighlighterImpl extends RangeMarkerImpl implements RangeHighlighterEx, Getter<RangeHighlighterEx> {
class RangeHighlighterImpl extends RangeMarkerImpl implements RangeHighlighterEx {
@SuppressWarnings({"InspectionUsingGrayColors", "UseJBColor"})
private static final Color NULL_COLOR = new Color(0, 0, 0); // must be new instance to work as a sentinel
private static final Key<Boolean> VISIBLE_IF_FOLDED = Key.create("visible.folded");
@@ -443,11 +442,6 @@ class RangeHighlighterImpl extends RangeMarkerImpl implements RangeHighlighterEx
getMarkupModel().removeHighlighter(this);
}
@Override
public RangeHighlighterImpl get() {
return this;
}
@Override
public int getLayer() {
RangeHighlighterTree.RHNode node = (RangeHighlighterTree.RHNode)(Object)myNode;
@@ -30,6 +30,11 @@ class RangeHighlighterTree extends RangeMarkerTree<RangeHighlighterEx> {
myMarkupModel = markupModel;
}
@Override
protected boolean keepIntervalsOnWeakReferences() {
return false;
}
@NotNull
MarkupIterator<RangeHighlighterEx> overlappingIterator(@NotNull TextRangeInterval rangeInterval, boolean onlyRenderedInGutter) {
MarkupIterator<RangeHighlighterEx> iterator =
@@ -84,13 +89,6 @@ class RangeHighlighterTree extends RangeMarkerTree<RangeHighlighterEx> {
myLayer = layer;
}
//range highlighters are strongly referenced
@Override
protected Getter<RangeHighlighterEx> createGetter(@NotNull RangeHighlighterEx interval) {
//noinspection unchecked
return (Getter<RangeHighlighterEx>)interval;
}
private void recalculateRenderFlags() {
boolean renderedInGutter = false;
for (Getter<RangeHighlighterEx> getter : intervals) {
@@ -3,10 +3,9 @@ package com.intellij.openapi.editor.impl;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.editor.ex.RangeHighlighterEx;
import com.intellij.openapi.util.Getter;
import org.jetbrains.annotations.NotNull;
class ErrorStripeMarkerImpl extends RangeMarkerImpl implements Getter<ErrorStripeMarkerImpl> {
class ErrorStripeMarkerImpl extends RangeMarkerImpl {
private final RangeHighlighterEx myHighlighter;
@@ -20,11 +19,6 @@ class ErrorStripeMarkerImpl extends RangeMarkerImpl implements Getter<ErrorStrip
return myHighlighter;
}
@Override
public ErrorStripeMarkerImpl get() {
return this;
}
@Override
public boolean isValid() {
return myHighlighter.isValid() && super.isValid();
@@ -2,10 +2,9 @@
package com.intellij.openapi.editor.impl;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.Getter;
import org.jetbrains.annotations.NotNull;
class ErrorStripeRangeMarkerTree extends RangeMarkerTree<ErrorStripeMarkerImpl> {
class ErrorStripeRangeMarkerTree extends HardReferencingRangeMarkerTree<ErrorStripeMarkerImpl> {
ErrorStripeRangeMarkerTree(@NotNull Document document) {
super(document);
@@ -44,9 +43,5 @@ class ErrorStripeRangeMarkerTree extends RangeMarkerTree<ErrorStripeMarkerImpl>
myLayer = layer;
}
@Override
protected Getter<ErrorStripeMarkerImpl> createGetter(@NotNull ErrorStripeMarkerImpl interval) {
return interval;
}
}
}
@@ -12,7 +12,7 @@ import com.intellij.util.DocumentUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class FoldRegionImpl extends RangeMarkerWithGetterImpl implements FoldRegion {
public class FoldRegionImpl extends RangeMarkerImpl implements FoldRegion {
private static final Key<Boolean> MUTE_INNER_HIGHLIGHTERS = Key.create("mute.inner.highlighters");
private static final Key<Boolean> SHOW_GUTTER_MARK_FOR_SINGLE_LINE = Key.create("show.gutter.mark.for.single.line");
@@ -30,7 +30,7 @@ public class FoldRegionImpl extends RangeMarkerWithGetterImpl implements FoldReg
@NotNull String placeholder,
@Nullable FoldingGroup group,
boolean shouldNeverExpand) {
super(editor.getDocument(), startOffset, endOffset,false);
super(editor.getDocument(), startOffset, endOffset,false, true);
myGroup = group;
myShouldNeverExpand = shouldNeverExpand;
myIsExpanded = true;
@@ -716,14 +716,14 @@ public class FoldingModelImpl extends InlayModel.SimpleAdapter
@NotNull
@Override
protected Node<FoldRegionImpl> createNewNode(@NotNull FoldRegionImpl key,
protected RMNode<FoldRegionImpl> createNewNode(@NotNull FoldRegionImpl key,
int start,
int end,
boolean greedyToLeft,
boolean greedyToRight,
boolean stickingToRight,
int layer) {
return new Node<FoldRegionImpl>(this, key, start, end, greedyToLeft, greedyToRight, stickingToRight) {
return new RMNode<FoldRegionImpl>(this, key, start, end, greedyToLeft, greedyToRight, stickingToRight) {
@Override
void onRemoved() {
for (Getter<FoldRegionImpl> getter : intervals) {
@@ -766,7 +766,7 @@ public class FoldingModelImpl extends InlayModel.SimpleAdapter
if (oldLength > 0 /* document change can cause regions to become equal*/) {
for (Object o : affected) {
//noinspection unchecked
Node<FoldRegionImpl> node = (Node<FoldRegionImpl>)o;
RMNode<FoldRegionImpl> node = (RMNode<FoldRegionImpl>)o;
FoldRegionImpl region = getRegion(node);
// region with the largest metric value is kept when several regions become identical after document change
// we want the largest collapsed region to survive
@@ -2,46 +2,19 @@
package com.intellij.openapi.editor.impl;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.util.Getter;
import org.jetbrains.annotations.NotNull;
/**
* {@link RangeMarkerTree} with intervals which are not collected when no one holds a reference to them.
*
* @see RangeMarkerWithGetterImpl
*/
class HardReferencingRangeMarkerTree<T extends RangeMarkerWithGetterImpl> extends RangeMarkerTree<T> {
class HardReferencingRangeMarkerTree<T extends RangeMarkerImpl> extends RangeMarkerTree<T> {
HardReferencingRangeMarkerTree(@NotNull Document document) {
super(document);
}
@NotNull
@Override
protected Node<T> createNewNode(@NotNull T key,
int start,
int end,
boolean greedyToLeft,
boolean greedyToRight,
boolean stickingToRight,
int layer) {
return new Node<>(this, key, start, end, greedyToLeft, greedyToRight, stickingToRight);
protected boolean keepIntervalsOnWeakReferences() {
return false;
}
static class Node<T extends RangeMarkerWithGetterImpl> extends RMNode<T> {
Node(@NotNull RangeMarkerTree<T> rangeMarkerTree,
@NotNull T key,
int start,
int end,
boolean greedyToLeft,
boolean greedyToRight,
boolean stickingToRight) {
super(rangeMarkerTree, key, start, end, greedyToLeft, greedyToRight, stickingToRight);
}
@Override
protected Getter<T> createGetter(@NotNull T interval) {
//noinspection unchecked
return (Getter<T>) interval;
}
}
}
@@ -15,7 +15,7 @@ import javax.swing.*;
import java.awt.*;
import java.util.Objects;
abstract class InlayImpl<R extends EditorCustomElementRenderer, T extends InlayImpl<?, ?>> extends RangeMarkerWithGetterImpl implements Inlay<R> {
abstract class InlayImpl<R extends EditorCustomElementRenderer, T extends InlayImpl<?, ?>> extends RangeMarkerImpl implements Inlay<R> {
static final Key<Integer> OFFSET_BEFORE_DISPOSAL = Key.create("inlay.offset.before.disposal");
@NotNull
@@ -28,7 +28,7 @@ abstract class InlayImpl<R extends EditorCustomElementRenderer, T extends InlayI
@SuppressWarnings("AbstractMethodCallInConstructor")
InlayImpl(@NotNull EditorImpl editor, int offset, boolean relatesToPrecedingText, @NotNull R renderer) {
super(editor.getDocument(), offset, offset, false);
super(editor.getDocument(), offset, offset, false, true);
myEditor = editor;
myRelatedToPrecedingText = relatesToPrecedingText;
myRenderer = renderer;
@@ -517,9 +517,9 @@ public final class InlayModelImpl implements InlayModel, PrioritizedDocumentList
@NotNull
@Override
protected Node<InlineInlayImpl<?>> createNewNode(@NotNull InlineInlayImpl key, int start, int end,
protected RMNode<InlineInlayImpl<?>> createNewNode(@NotNull InlineInlayImpl key, int start, int end,
boolean greedyToLeft, boolean greedyToRight, boolean stickingToRight, int layer) {
return new Node<InlineInlayImpl<?>>(this, key, start, end, greedyToLeft, greedyToRight, stickingToRight) {
return new RMNode<InlineInlayImpl<?>>(this, key, start, end, greedyToLeft, greedyToRight, stickingToRight) {
@Override
void addIntervalsFrom(@NotNull IntervalNode<InlineInlayImpl<?>> otherNode) {
super.addIntervalsFrom(otherNode);
@@ -13,7 +13,7 @@ import java.util.function.IntSupplier;
* Only 'non-greedy' markers with zero length are supported (for such markers start offset is always equal to end offset).
* Not thread safe - cannot be used from multiple threads simultaneously.
*/
class MarkerTreeWithPartialSums<T extends RangeMarkerWithGetterImpl & IntSupplier> extends HardReferencingRangeMarkerTree<T> {
class MarkerTreeWithPartialSums<T extends RangeMarkerImpl & IntSupplier> extends HardReferencingRangeMarkerTree<T> {
MarkerTreeWithPartialSums(@NotNull Document document) {
super(document);
}
@@ -53,13 +53,13 @@ class MarkerTreeWithPartialSums<T extends RangeMarkerWithGetterImpl & IntSupplie
@NotNull
@Override
protected HardReferencingRangeMarkerTree.Node<T> createNewNode(@NotNull T key,
int start,
int end,
boolean greedyToLeft,
boolean greedyToRight,
boolean stickingToRight,
int layer) {
protected RMNode<T> createNewNode(@NotNull T key,
int start,
int end,
boolean greedyToLeft,
boolean greedyToRight,
boolean stickingToRight,
int layer) {
assert start == end;
assert !greedyToLeft;
assert !greedyToRight;
@@ -72,7 +72,7 @@ class MarkerTreeWithPartialSums<T extends RangeMarkerWithGetterImpl & IntSupplie
((Node<T>)node).recalculateSubTreeSum();
}
static class Node<T extends RangeMarkerWithGetterImpl & IntSupplier> extends HardReferencingRangeMarkerTree.Node<T> {
static class Node<T extends RangeMarkerImpl & IntSupplier> extends RMNode<T> {
private int subtreeSum;
Node(@NotNull RangeMarkerTree<T> rangeMarkerTree,
@@ -1,20 +0,0 @@
// Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package com.intellij.openapi.editor.impl;
import com.intellij.openapi.editor.ex.DocumentEx;
import com.intellij.openapi.util.Getter;
import org.jetbrains.annotations.NotNull;
/**
* @see HardReferencingRangeMarkerTree
*/
class RangeMarkerWithGetterImpl extends RangeMarkerImpl implements Getter<RangeMarkerWithGetterImpl> {
RangeMarkerWithGetterImpl(@NotNull DocumentEx document, int start, int end, boolean register) {
super(document, start, end, register, true);
}
@Override
public final RangeMarkerWithGetterImpl get() {
return this;
}
}
@@ -187,7 +187,7 @@ public class MarkerTreeWithPartialSumsTest extends AbstractEditorTest {
return result;
}
private class MyRange extends RangeMarkerWithGetterImpl implements IntSupplier {
private class MyRange extends RangeMarkerImpl implements IntSupplier {
private int myValue;
MyRange(int offset, int value) {
@@ -195,7 +195,7 @@ public class MarkerTreeWithPartialSumsTest extends AbstractEditorTest {
}
MyRange(int offset, int value, boolean stickToRight) {
super(myDocument, offset, offset, false);
super(myDocument, offset, offset, false, true);
myValue = value;
myTree.addInterval(this, offset, offset, false, false, stickToRight, 0);
}