Merge "Allow disabling inlining for development version of R8"
diff --git a/src/main/java/com/android/tools/r8/graph/DexCallSite.java b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
index e690317..11bca5a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCallSite.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
@@ -118,10 +118,14 @@
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
assert method != null;
+ // Since collectIndexedItems() is called in transactions that may be rolled back, we may end up
+ // setting this.method and this.instructionOffset more than once. If we do set them more than
+ // once, then we must have the same values for method and instructionOffset every time.
+ assert this.method == null || this.method == method;
+ assert this.instructionOffset == 0 || this.instructionOffset == instructionOffset;
+ this.method = method;
+ this.instructionOffset = instructionOffset;
if (indexedItems.addCallSite(this)) {
- assert this.method == null;
- this.method = method;
- this.instructionOffset = instructionOffset;
methodName.collectIndexedItems(indexedItems, method, instructionOffset);
methodProto.collectIndexedItems(indexedItems, method, instructionOffset);
bootstrapMethod.collectIndexedItems(indexedItems, method, instructionOffset);
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index df30c18..0976087 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -77,6 +77,7 @@
public static final int REGISTER_CANDIDATE_NOT_FOUND = -1;
public static final int MIN_CONSTANT_FREE_FOR_POSITIONS = 5;
+ public static final int EXCEPTION_INTERVALS_OVERLAP_CUTOFF = 500;
private enum ArgumentReuseMode {
ALLOW_ARGUMENT_REUSE,
@@ -1357,7 +1358,7 @@
// If there are that many move exception intervals we don't spent the time
// going through them all. In that case it is unlikely that we can reuse the move exception
// register in any case.
- if (moveExceptionIntervals.size() > 1000) {
+ if (moveExceptionIntervals.size() > EXCEPTION_INTERVALS_OVERLAP_CUTOFF) {
return true;
}
for (LiveIntervals moveExceptionInterval : moveExceptionIntervals) {
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
index 74600f4..c8e6e4c 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java
@@ -11,7 +11,10 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.utils.CfgPrinter;
+import it.unimi.dsi.fastutil.ints.IntArrayList;
import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.TreeSet;
@@ -20,12 +23,15 @@
public class LiveIntervals implements Comparable<LiveIntervals> {
public static final int NO_REGISTER = Integer.MIN_VALUE;
+ public static final int CHILDREN_SORTING_CUTOFF = 100;
private final Value value;
private LiveIntervals nextConsecutive;
private LiveIntervals previousConsecutive;
private final LiveIntervals splitParent;
private final List<LiveIntervals> splitChildren = new ArrayList<>();
+ private final IntArrayList sortedSplitChildrenEnds = new IntArrayList();
+ private boolean sortedChildren = false;
private List<LiveRange> ranges = new ArrayList<>();
private final TreeSet<LiveIntervalsUse> uses = new TreeSet<>();
private int numberOfConsecutiveRegisters = -1;
@@ -189,6 +195,26 @@
return splitChildren.size() != 0;
}
+ private void sortSplitChildrenIfNeeded() {
+ if (!sortedChildren) {
+ splitChildren.sort(Comparator.comparingInt(LiveIntervals::getEnd));
+ sortedSplitChildrenEnds.clear();
+ for (LiveIntervals splitChild : splitChildren) {
+ sortedSplitChildrenEnds.add(splitChild.getEnd());
+ }
+ assert sortedChildrenConsistent();
+ sortedChildren = true;
+ }
+ }
+
+ private boolean sortedChildrenConsistent() {
+ for (int i = 0; i < splitChildren.size(); i++) {
+ assert splitChildren.get(i).getEnd() == sortedSplitChildrenEnds.getInt(i);
+ assert i == 0 || sortedSplitChildrenEnds.getInt(i - 1) <= sortedSplitChildrenEnds.getInt(i);
+ }
+ return true;
+ }
+
public List<LiveIntervals> getSplitChildren() {
return splitChildren;
}
@@ -404,6 +430,7 @@
start = toGapPosition(start);
LiveIntervals splitChild = new LiveIntervals(splitParent);
splitParent.splitChildren.add(splitChild);
+ splitParent.sortedChildren = false;
List<LiveRange> beforeSplit = new ArrayList<>();
List<LiveRange> afterSplit = new ArrayList<>();
if (start == getEnd()) {
@@ -460,7 +487,19 @@
// whose end is the instruction number. This is needed when transitioning values across
// control-flow boundaries.
LiveIntervals matchingEnd = getEnd() == instructionNumber ? this : null;
- for (LiveIntervals splitChild : splitChildren) {
+ // When there are many children, avoid looking at the ones for which the end is before
+ // the instruction number by doing a binary search for the first candidate whose end is after
+ // the instruction number.
+ int firstCandidate = 0;
+ if (splitChildren.size() > CHILDREN_SORTING_CUTOFF) {
+ sortSplitChildrenIfNeeded();
+ firstCandidate = Collections.binarySearch(sortedSplitChildrenEnds, instructionNumber);
+ if (firstCandidate < 0) {
+ firstCandidate = -(firstCandidate + 1);
+ }
+ }
+ for (int i = firstCandidate; i < splitChildren.size(); i++) {
+ LiveIntervals splitChild = splitChildren.get(i);
if (splitChild.getStart() <= instructionNumber && splitChild.getEnd() > instructionNumber) {
return splitChild;
}
diff --git a/third_party/gmscore/gmscore_v10.tar.gz.sha1 b/third_party/gmscore/gmscore_v10.tar.gz.sha1
index 15cab81..535f285 100644
--- a/third_party/gmscore/gmscore_v10.tar.gz.sha1
+++ b/third_party/gmscore/gmscore_v10.tar.gz.sha1
@@ -1 +1 @@
-43838ee1687ff48e866396dfd4b99415662fbea6
\ No newline at end of file
+fd2bc157ba2d61a19804107df47e0f87926b210d
\ No newline at end of file
diff --git a/third_party/gmscore/gmscore_v9.tar.gz.sha1 b/third_party/gmscore/gmscore_v9.tar.gz.sha1
index 5983b5b..0ff5779 100644
--- a/third_party/gmscore/gmscore_v9.tar.gz.sha1
+++ b/third_party/gmscore/gmscore_v9.tar.gz.sha1
@@ -1 +1 @@
-0066065faeb293c5a850d3319f2cb8a48d1e760d
\ No newline at end of file
+4bfdee0d2287b061164f984dfa4ad6ec8617effa
\ No newline at end of file
diff --git a/tools/upload_to_x20.py b/tools/upload_to_x20.py
index 08e48d9..1efacf5 100755
--- a/tools/upload_to_x20.py
+++ b/tools/upload_to_x20.py
@@ -39,7 +39,7 @@
dest = os.path.join(GMSCORE_DEPS, sha1)
print 'Uploading to %s' % dest
shutil.copyfile(filename, dest)
- os.chmod(dest, stat.S_IRWXU | stat.S_IROTH | stat.S_IXOTH | stat.S_IRWXG)
+ subprocess.check_call(['chmod', '664', dest])
sha1_file = '%s.sha1' % filename
with open(sha1_file, 'w') as output:
output.write(sha1)