@@ -471,7 +471,10 @@ public String toString() {
471
471
Interval next ;
472
472
473
473
/**
474
- * Link to next spill interval in a list of intervals that ends with {@code null}.
474
+ * Link to the next spill interval in a list of intervals that ends with {@code null}. This
475
+ * field is only valid when iterating intervals starting from
476
+ * {@link LinearScanWalker#spillIntervals}. Only the head of the list of cleared so this field
477
+ * can contain stale values.
475
478
*/
476
479
Interval spillNext ;
477
480
@@ -655,8 +658,14 @@ void removeFirstUsePos() {
655
658
private int rangePairLength ;
656
659
657
660
/**
658
- * The list [{@code from}, {@code to}) pairs representing a range of integers from a start
661
+ * The list of [{@code from}, {@code to}) pairs representing a range of integers from a start
659
662
* (inclusive) to an end (exclusive).
663
+ * <p>
664
+ * All values are positive and the ranges are always sorted such that {@code from} is less than
665
+ * {@code to} and {@code to} is less than the next {@code from}. This means that the integers in
666
+ * the array are sorted and disjoint. The {@code to} of a range will never equal the
667
+ * {@code from} of the next range as during interval construction such ranges are merged into a
668
+ * single range. {@link #rangePairLength} is portion of this array that is valid.
660
669
*/
661
670
private int [] rangePairs ;
662
671
@@ -683,6 +692,11 @@ boolean isEmpty() {
683
692
private void ensureCapacity (int minCapacity ) {
684
693
if (minCapacity > rangePairs .length ) {
685
694
int oldCapacity = rangePairs .length ;
695
+ /*
696
+ * This is basically the ArrayList expansion policy but in practice these arrays are
697
+ * relatively short so the policy isn't critical. Roughly 30% of intervals have a single
698
+ * element and 90% have less than 10.
699
+ */
686
700
rangePairs = Arrays .copyOf (rangePairs , oldCapacity + Math .max (minCapacity - oldCapacity , oldCapacity >> 1 ));
687
701
}
688
702
}
@@ -741,34 +755,36 @@ public String getRangesAsString() {
741
755
}
742
756
743
757
/**
744
- * Copy the content of {@code other} into this list starting after splitPos.
758
+ * Splits this interval at a specified position, creating a new child interval and updating the
759
+ * range information for both this interval and the new child.
745
760
*/
746
- void split (Interval other , int splitPos ) {
761
+ Interval createSplit (int splitPos , LinearScan allocator ) {
762
+ Interval newInterval = newSplitChild (allocator );
747
763
// split the ranges
748
764
int curRangeIndex = 0 ;
749
- while (curRangeIndex != other . rangePairLength && other . to (curRangeIndex ) <= splitPos ) {
765
+ while (curRangeIndex != rangePairLength && to (curRangeIndex ) <= splitPos ) {
750
766
curRangeIndex += 2 ;
751
767
}
752
- assert !(curRangeIndex == other . rangePairLength ) : "split interval after end of last range" ;
768
+ assert !(curRangeIndex == rangePairLength ) : "split interval after end of last range" ;
753
769
754
- if (other . from (curRangeIndex ) < splitPos ) {
770
+ if (from (curRangeIndex ) < splitPos ) {
755
771
// Splitting a pair
756
- rangePairs = Arrays .copyOfRange (other . rangePairs , curRangeIndex , other . rangePairLength );
757
- rangePairLength = rangePairs .length ;
758
- if (rangePairLength > 0 ) {
759
- rangePairs [0 ] = splitPos ;
772
+ newInterval . rangePairs = Arrays .copyOfRange (rangePairs , curRangeIndex , rangePairLength );
773
+ newInterval . rangePairLength = newInterval . rangePairs .length ;
774
+ if (newInterval . rangePairLength > 0 ) {
775
+ newInterval . rangePairs [0 ] = splitPos ;
760
776
}
761
- other . rangePairLength = curRangeIndex + 2 ;
762
- other . rangePairs [other . rangePairLength - 1 ] = splitPos ;
777
+ rangePairLength = curRangeIndex + 2 ;
778
+ rangePairs [rangePairLength - 1 ] = splitPos ;
763
779
} else {
764
780
// Splitting between two ranges
765
- rangePairs = Arrays .copyOfRange (other . rangePairs , curRangeIndex , other . rangePairLength );
766
- rangePairLength = rangePairs .length ;
767
- other . rangePairLength = curRangeIndex ;
781
+ newInterval . rangePairs = Arrays .copyOfRange (rangePairs , curRangeIndex , rangePairLength );
782
+ newInterval . rangePairLength = newInterval . rangePairs .length ;
783
+ rangePairLength = curRangeIndex ;
768
784
}
785
+ return newInterval ;
769
786
}
770
787
771
- // range iteration
772
788
/**
773
789
* Resets the range iteration to the beginning of the interval's ranges.
774
790
*/
@@ -848,14 +864,15 @@ boolean isAtEnd() {
848
864
}
849
865
}
850
866
851
- private boolean rangeIntersects (int rangeIndex , Interval other , int otherRangeIndex ) {
852
- int start = Math .max (from (rangeIndex ), other .from (otherRangeIndex ));
853
- int end = Math .min (to (rangeIndex ), other .to (otherRangeIndex ));
854
- return start < end ;
855
- }
856
-
857
867
/**
858
- * Checks if this interval intersects with a given interval using a binary search algorithm.
868
+ * Checks if this interval intersects with a given interval using a binary search algorithm. The
869
+ * method iterates through the ranges of the shorter interval and performs a binary search in
870
+ * the ranges of the longer interval to check for intersections.
871
+ * <p>
872
+ * The method proceeds by directly iterating over the shorter interval and uses
873
+ * {@link Arrays#binarySearch(int[], int)} to look for the current {@code from} in the longer
874
+ * interval. If binarySearch finds the value in the long interval then there are two cases. If
875
+ * the position of the value is even, then this is the from value which means
859
876
*/
860
877
public boolean binarySearchInterval (Interval currentInterval ) {
861
878
Interval longInterval ;
@@ -876,40 +893,66 @@ public boolean binarySearchInterval(Interval currentInterval) {
876
893
int shortTo = shortInterval .to (shortCurrentRangeIndex );
877
894
int searchResult = Arrays .binarySearch (longArray , longCurrentRangeIndex , longInterval .rangePairLength , shortFrom );
878
895
if (searchResult >= 0 ) {
879
- /*
880
- * The search found the other value. If it's even then the range was found because
881
- * short.from == long.from.
882
- */
883
896
if ((searchResult & 1 ) == 0 ) {
884
- assert shortInterval .rangeIntersects (shortCurrentRangeIndex , longInterval , searchResult );
897
+ /*
898
+ * The search found the other value. This means long contains either [shortFrom,
899
+ * x) or [x, shortFrom). If it's even then the range was found because short
900
+ * contains [shortFrom, x) and long contains [shortFrom, y).
901
+ */
885
902
return true ;
886
903
}
887
- /*
888
- * short.from == long.to so short range doesn't intersect with current range in
889
- * long. Check the next range for overlap.
890
- */
904
+ // An odd searchResult means that shortFrom is the to of a range in long. In this
905
+ // case the ranges are [shortFrom, shortTo) in short and [x, shortFrom) in long so
906
+ // since the ranges are half open they don't intersect. Move to the next range in
907
+ // long and fall through to check for overlap. This will check if the next range in
908
+ // long begins before shortTo, which is the only way this short range could overlap.
909
+ //
910
+ // @formatter:off
911
+ // short [shortFrom, shortTo)
912
+ // long intersects [x, shortFrom) [nextLongFrom, y)
913
+ // long doesn't intersect [x, shortFrom) [nextLongFrom, y)
914
+ // @formatter:on
891
915
longCurrentRangeIndex = searchResult + 1 ;
892
916
} else {
917
+ /*
918
+ * If an element isn't found, binarySearch returns the proper insertion location as
919
+ * (-(insertion point) - 1 so reverse this computation;
920
+ */
893
921
int insertPoint = -(searchResult + 1 );
894
922
if ((insertPoint & 1 ) != 0 ) {
895
- /*
896
- * The insertion point is odd which means long.from is between short.from and
897
- * short.to so they directly intersect.
898
- */
899
- assert shortInterval .rangeIntersects (shortCurrentRangeIndex , longInterval , insertPoint & ~1 );
923
+ // The insertion point is odd which means shortFrom > longFrom and shortFrom <
924
+ // longTo which means they definitely intersect.
925
+ //
926
+ // @formatter:off
927
+ // short [shortFrom, shortTo]
928
+ // long intersects [x, y)
929
+ // long intersects [x, y)
930
+ // @formatter:on
900
931
return true ;
901
932
}
933
+ // The insertion point is even which means shortFrom is less than the longFrom, so
934
+ // fall through and check if the current range in long begins before shortTo, which
935
+ // is the only way this short range could overlap.
936
+ //
937
+ // @formatter:off
938
+ // short [shortFrom, shortTo)
939
+ // long intersects [nextLongFrom, y]
940
+ // long doesn't intersect [nextLongFrom, y]
941
+ // @formatter:on
902
942
longCurrentRangeIndex = insertPoint ;
903
943
}
904
944
if (longCurrentRangeIndex == longInterval .rangePairLength ) {
905
945
return false ;
906
946
}
907
- // Check if the next long range begins before the end of the short range.
947
+ // Check if the long range begins before the end of the short range.
908
948
int longFrom = longInterval .from (longCurrentRangeIndex );
909
949
if (longFrom < shortTo ) {
910
- assert shortInterval .rangeIntersects (shortCurrentRangeIndex , longInterval , longCurrentRangeIndex );
911
950
return true ;
912
951
}
952
+ /*
953
+ * The current short range doesn't intersect with any range in long so move on to the
954
+ * next.
955
+ */
913
956
shortCurrentRangeIndex += 2 ;
914
957
}
915
958
return false ;
@@ -920,7 +963,7 @@ public boolean binarySearchInterval(Interval currentInterval) {
920
963
/**
921
964
* Retrieves an element from an integer array using {@link Unsafe} for direct memory access. The
922
965
* ranges checks add too much overhead and range check optimizations are unabled to eliminate
923
- * them so we rely on the correct properly checking iteration ranges .
966
+ * them so we rely on the iteration logic to properly respect the bounds .
924
967
*/
925
968
private static int elementGet (int [] array , int index ) {
926
969
return UNSAFE .getInt (array , Unsafe .ARRAY_INT_BASE_OFFSET + (long ) index * Unsafe .ARRAY_INT_INDEX_SCALE );
@@ -937,65 +980,72 @@ int currentIntersectsAt(Interval other) {
937
980
return -1 ;
938
981
}
939
982
940
- return intersectsAt (this .currentRangeIndex , other , other .currentRangeIndex );
983
+ return intersectsAt (this .currentRangeIndex , other , other .currentRangeIndex , Integer . MAX_VALUE );
941
984
}
942
985
943
986
/**
944
987
* Checks if this interval intersects with a given interval, starting from the first range.
945
988
*/
946
989
boolean intersects (Interval i ) {
947
- return intersectsAt (0 , i , 0 ) != -1 ;
990
+ return intersectsAt (0 , i , 0 , Integer . MAX_VALUE ) != -1 ;
948
991
}
949
992
950
993
/**
951
994
* Checks if this interval intersects with a given interval at a specified range iteration
952
995
* position. If an intersection is found, it returns the position of the intersection. If no
953
996
* intersection is found, it returns -1.
954
997
*/
955
- private int intersectsAt (int thisCurrentRangeIndex , Interval other , int otherCurrentRangeIndex ) {
998
+ private int intersectsAt (int thisCurrentRangeIndex , Interval other , int otherCurrentRangeIndex , int limit ) {
956
999
int thisRangeIndex = thisCurrentRangeIndex ;
957
1000
int otherRangeIndex = otherCurrentRangeIndex ;
958
1001
int [] thisRangePairs = this .rangePairs ;
959
1002
int [] otherRangePairs = other .rangePairs ;
1003
+ int thisFrom = elementGet (thisRangePairs , thisRangeIndex );
1004
+ int otherFrom = elementGet (otherRangePairs , otherRangeIndex );
960
1005
do {
961
- int r1from = elementGet (thisRangePairs , thisRangeIndex );
962
- int r2from = elementGet (otherRangePairs , otherRangeIndex );
963
- int r1to = elementGet (thisRangePairs , thisRangeIndex + 1 );
964
- if (r1from < r2from ) {
965
- if (r1to <= r2from ) {
1006
+ assert thisFrom == elementGet (thisRangePairs , thisRangeIndex ) : "mismatch" ;
1007
+ assert otherFrom == elementGet (otherRangePairs , otherRangeIndex ) : "mismatch" ;
1008
+
1009
+ if (thisFrom > limit && otherFrom > limit ) {
1010
+ return -1 ;
1011
+ }
1012
+ int thisTo = elementGet (thisRangePairs , thisRangeIndex + 1 );
1013
+ if (thisFrom < otherFrom ) {
1014
+ if (thisTo <= otherFrom ) {
966
1015
thisRangeIndex += 2 ;
967
1016
if (thisRangeIndex == rangePairLength ) {
968
1017
return -1 ;
969
1018
}
1019
+ thisFrom = elementGet (thisRangePairs , thisRangeIndex );
970
1020
} else {
971
- return r2from ;
1021
+ return otherFrom ;
972
1022
}
973
- } else {
974
- if (r2from < r1from ) {
975
- if (elementGet (otherRangePairs , otherRangeIndex + 1 ) <= r1from ) {
976
- otherRangeIndex += 2 ;
977
- if (otherRangeIndex == other .rangePairLength ) {
978
- return -1 ;
979
- }
980
- } else {
981
- return r1from ;
1023
+ } else if (thisFrom > otherFrom ) {
1024
+ if (elementGet (otherRangePairs , otherRangeIndex + 1 ) <= thisFrom ) {
1025
+ otherRangeIndex += 2 ;
1026
+ if (otherRangeIndex == other .rangePairLength ) {
1027
+ return -1 ;
982
1028
}
983
- } else { // r1.from()() == r2.from()()
984
- if (r1from == r1to ) {
985
- thisRangeIndex += 2 ;
986
- if (thisRangeIndex == rangePairLength ) {
987
- return -1 ;
988
- }
989
- } else {
990
- if (r2from == elementGet (otherRangePairs , otherRangeIndex + 1 )) {
991
- otherRangeIndex += 2 ;
992
- if (otherRangeIndex == other .rangePairLength ) {
993
- return -1 ;
994
- }
995
- } else {
996
- return r1from ;
997
- }
1029
+ otherFrom = elementGet (otherRangePairs , otherRangeIndex );
1030
+ } else {
1031
+ return thisFrom ;
1032
+ }
1033
+ } else if (thisFrom == thisTo ) {
1034
+ // thisFrom == otherFrom
1035
+ thisRangeIndex += 2 ;
1036
+ if (thisRangeIndex == rangePairLength ) {
1037
+ return -1 ;
1038
+ }
1039
+ thisFrom = elementGet (thisRangePairs , thisRangeIndex );
1040
+ } else {
1041
+ if (otherFrom == elementGet (otherRangePairs , otherRangeIndex + 1 )) {
1042
+ otherRangeIndex += 2 ;
1043
+ if (otherRangeIndex == other .rangePairLength ) {
1044
+ return -1 ;
998
1045
}
1046
+ otherFrom = elementGet (otherRangePairs , otherRangeIndex );
1047
+ } else {
1048
+ return thisFrom ;
999
1049
}
1000
1050
}
1001
1051
} while (true ); // TERMINATION ARGUMENT: guarded by the number of ranges reachable from this
@@ -1019,57 +1069,7 @@ int currentIntersectsAtLimit(Interval other, int limit) {
1019
1069
return -1 ;
1020
1070
}
1021
1071
1022
- int r1current = this .currentRangeIndex ;
1023
- int r2current = other .currentRangeIndex ;
1024
- int [] thisArray = this .rangePairs ;
1025
- int [] otherArray = other .rangePairs ;
1026
- do {
1027
- int r1from = elementGet (thisArray , r1current );
1028
- int r2from = elementGet (otherArray , r2current );
1029
- if (r1from > limit && r2from > limit ) {
1030
- return -1 ;
1031
- }
1032
-
1033
- int r1to = elementGet (thisArray , r1current + 1 );
1034
- if (r1from < r2from ) {
1035
- if (r1to <= r2from ) {
1036
- r1current += 2 ;
1037
- if (r1current == rangePairLength ) {
1038
- return -1 ;
1039
- }
1040
- } else {
1041
- return r2from ;
1042
- }
1043
- } else {
1044
- if (r2from < r1from ) {
1045
- if (elementGet (otherArray , r2current + 1 ) <= r1from ) {
1046
- r2current += 2 ;
1047
- if (r2current == other .rangePairLength ) {
1048
- return -1 ;
1049
- }
1050
- } else {
1051
- return r1from ;
1052
- }
1053
- } else { // r1.from()() == r2.from()()
1054
- if (r1from == r1to ) {
1055
- r1current += 2 ;
1056
- if (r1current == rangePairLength ) {
1057
- return -1 ;
1058
- }
1059
- } else {
1060
- if (r2from == elementGet (otherArray , r2current + 1 )) {
1061
- r2current += 2 ;
1062
- if (r2current == other .rangePairLength ) {
1063
- return -1 ;
1064
- }
1065
- } else {
1066
- return r1from ;
1067
- }
1068
- }
1069
- }
1070
- }
1071
- } while (true ); // TERMINATION ARGUMENT: guarded by the number of ranges reachable from this
1072
- // and other
1072
+ return intersectsAt (currentRangeIndex , other , other .currentRangeIndex , limit );
1073
1073
}
1074
1074
1075
1075
Interval (AllocatableValue operand , int operandNumber , Interval intervalEndMarker ) {
@@ -1439,8 +1439,7 @@ Interval split(int splitPos, LinearScan allocator) {
1439
1439
assert LIRValueUtil .isVariable (operand ) : "cannot split fixed intervals" ;
1440
1440
1441
1441
// allocate new interval
1442
- Interval result = newSplitChild (allocator );
1443
- result .split (this , splitPos );
1442
+ Interval result = createSplit (splitPos , allocator );
1444
1443
1445
1444
// split list of use positions
1446
1445
result .usePosList = usePosList .splitAt (splitPos );
0 commit comments