Merge "Don't associate local info with argument moves."
diff --git a/src/main/java/com/android/tools/r8/DexSegments.java b/src/main/java/com/android/tools/r8/DexSegments.java
index 5f49ba7..501fecc 100644
--- a/src/main/java/com/android/tools/r8/DexSegments.java
+++ b/src/main/java/com/android/tools/r8/DexSegments.java
@@ -117,7 +117,7 @@
       for (Resource resource : app.getDexProgramResources()) {
         for (Segment segment: DexFileReader.parseMapFrom(resource.getStream(closer))) {
           int value = result.computeIfAbsent(segment.typeName(), (key) -> 0);
-          result.put(segment.typeName(), value + segment.getSize());
+          result.put(segment.typeName(), value + segment.size());
         }
       }
     }
diff --git a/src/main/java/com/android/tools/r8/dex/DexFileReader.java b/src/main/java/com/android/tools/r8/dex/DexFileReader.java
index 3342be6..a064494 100644
--- a/src/main/java/com/android/tools/r8/dex/DexFileReader.java
+++ b/src/main/java/com/android/tools/r8/dex/DexFileReader.java
@@ -125,11 +125,11 @@
       return;
     }
     Segment segment = lookupSegment(Constants.TYPE_CODE_ITEM);
-    if (segment.size == 0) {
+    if (segment.length == 0) {
       return;
     }
     file.position(segment.offset);
-    for (int i = 0; i < segment.size; i++) {
+    for (int i = 0; i < segment.length; i++) {
       file.align(4);  // code items are 4 byte aligned.
       int offset = file.position();
       DexCode code = parseCodeItem();
@@ -590,23 +590,23 @@
 
   void addClassDefsTo(Consumer<DexClass> classCollection) {
     final Segment segment = lookupSegment(Constants.TYPE_CLASS_DEF_ITEM);
-    final int size = segment.size;
-    indexedItems.initializeClasses(size);
-    if (size == 0) {
+    final int length = segment.length;
+    indexedItems.initializeClasses(length);
+    if (length == 0) {
       return;
     }
     file.position(segment.offset);
 
-    int[] classIndices = new int[size];
-    int[] accessFlags = new int[size];
-    int[] superclassIndices = new int[size];
-    int[] interfacesOffsets = new int[size];
-    int[] sourceFileIndices = new int[size];
-    int[] annotationsOffsets = new int[size];
-    int[] classDataOffsets = new int[size];
-    int[] staticValuesOffsets = new int[size];
+    int[] classIndices = new int[length];
+    int[] accessFlags = new int[length];
+    int[] superclassIndices = new int[length];
+    int[] interfacesOffsets = new int[length];
+    int[] sourceFileIndices = new int[length];
+    int[] annotationsOffsets = new int[length];
+    int[] classDataOffsets = new int[length];
+    int[] staticValuesOffsets = new int[length];
 
-    for (int i = 0; i < size; i++) {
+    for (int i = 0; i < length; i++) {
       if (Log.ENABLED) {
         Log.verbose(getClass(), "Reading ClassDef @ 0x%08x.", file.position());
       }
@@ -620,7 +620,7 @@
       staticValuesOffsets[i] = file.getUint();
     }
 
-    for (int i = 0; i < size; i++) {
+    for (int i = 0; i < length; i++) {
       int superclassIdx = superclassIndices[i];
       DexType superclass = superclassIdx == NO_INDEX ? null : indexedItems.getType(superclassIdx);
       int srcIdx = sourceFileIndices[i];
@@ -677,12 +677,12 @@
 
   private void parseStringIDs() {
     Segment segment = lookupSegment(Constants.TYPE_STRING_ID_ITEM);
-    stringIDs = new int[segment.size];
-    if (segment.size == 0) {
+    stringIDs = new int[segment.length];
+    if (segment.length == 0) {
       return;
     }
     file.position(segment.offset);
-    for (int i = 0; i < segment.size; i++) {
+    for (int i = 0; i < segment.length; i++) {
       stringIDs[i] = file.getUint();
     }
   }
@@ -715,7 +715,7 @@
         Segment segment = result[i];
         int nextOffset = i < result.length - 1 ? result[i + 1].offset : segment.offset;
         Log.debug(this.getClass(), "Read segment 0x%04x @ 0x%08x #items %08d size 0x%08x.",
-            segment.type, segment.offset, segment.size, nextOffset - segment.offset);
+            segment.type, segment.offset, segment.length, nextOffset - segment.offset);
       }
     }
     for (int i = 0; i < mapSize - 1; i++) {
@@ -823,48 +823,48 @@
 
   private static void populateMethodHandles(DexFileReader reader) {
     Segment segment = reader.lookupSegment(Constants.TYPE_METHOD_HANDLE_ITEM);
-    reader.indexedItems.initializeMethodHandles(segment.size);
-    for (int i = 0; i < segment.size; i++) {
+    reader.indexedItems.initializeMethodHandles(segment.length);
+    for (int i = 0; i < segment.length; i++) {
       reader.indexedItems.setMethodHandle(i, reader.methodHandleAt(i));
     }
   }
 
   private static void populateCallSites(DexFileReader reader) {
     Segment segment = reader.lookupSegment(Constants.TYPE_CALL_SITE_ID_ITEM);
-    reader.indexedItems.initializeCallSites(segment.size);
-    for (int i = 0; i < segment.size; i++) {
+    reader.indexedItems.initializeCallSites(segment.length);
+    for (int i = 0; i < segment.length; i++) {
       reader.indexedItems.setCallSites(i, reader.callSiteAt(i));
     }
   }
 
   private static void populateTypes(DexFileReader reader) {
     Segment segment = reader.lookupSegment(Constants.TYPE_TYPE_ID_ITEM);
-    reader.indexedItems.initializeTypes(segment.size);
-    for (int i = 0; i < segment.size; i++) {
+    reader.indexedItems.initializeTypes(segment.length);
+    for (int i = 0; i < segment.length; i++) {
       reader.indexedItems.setType(i, reader.typeAt(i));
     }
   }
 
   private static void populateFields(DexFileReader reader) {
     Segment segment = reader.lookupSegment(Constants.TYPE_FIELD_ID_ITEM);
-    reader.indexedItems.initializeFields(segment.size);
-    for (int i = 0; i < segment.size; i++) {
+    reader.indexedItems.initializeFields(segment.length);
+    for (int i = 0; i < segment.length; i++) {
       reader.indexedItems.setField(i, reader.fieldAt(i));
     }
   }
 
   private static void populateProtos(DexFileReader reader) {
     Segment segment = reader.lookupSegment(Constants.TYPE_PROTO_ID_ITEM);
-    reader.indexedItems.initializeProtos(segment.size);
-    for (int i = 0; i < segment.size; i++) {
+    reader.indexedItems.initializeProtos(segment.length);
+    for (int i = 0; i < segment.length; i++) {
       reader.indexedItems.setProto(i, reader.protoAt(i));
     }
   }
 
   private static void populateMethods(DexFileReader reader) {
     Segment segment = reader.lookupSegment(Constants.TYPE_METHOD_ID_ITEM);
-    reader.indexedItems.initializeMethods(segment.size);
-    for (int i = 0; i < segment.size; i++) {
+    reader.indexedItems.initializeMethods(segment.length);
+    for (int i = 0; i < segment.length; i++) {
       reader.indexedItems.setMethod(i, reader.methodAt(i));
     }
   }
@@ -884,7 +884,7 @@
 
   private DexType typeAt(int index) {
     Segment segment = lookupSegment(Constants.TYPE_TYPE_ID_ITEM);
-    if (index >= segment.size) {
+    if (index >= segment.length) {
       return null;
     }
     int offset = segment.offset + (Constants.TYPE_TYPE_ID_ITEM_SIZE * index);
@@ -894,7 +894,7 @@
 
   private DexField fieldAt(int index) {
     Segment segment = lookupSegment(Constants.TYPE_FIELD_ID_ITEM);
-    if (index >= segment.size) {
+    if (index >= segment.length) {
       return null;
     }
     int offset = segment.offset + (Constants.TYPE_FIELD_ID_ITEM_SIZE * index);
@@ -910,7 +910,7 @@
 
   private DexMethodHandle methodHandleAt(int index) {
     Segment segment = lookupSegment(Constants.TYPE_METHOD_HANDLE_ITEM);
-    if (index >= segment.size) {
+    if (index >= segment.length) {
       return null;
     }
     int offset = segment.offset + (Constants.TYPE_METHOD_HANDLE_ITEM_SIZE * index);
@@ -942,7 +942,7 @@
 
   private DexCallSite callSiteAt(int index) {
     Segment segment = lookupSegment(Constants.TYPE_CALL_SITE_ID_ITEM);
-    if (index >= segment.size) {
+    if (index >= segment.length) {
       return null;
     }
     int callSiteOffset =
@@ -963,7 +963,7 @@
 
   private DexProto protoAt(int index) {
     Segment segment = lookupSegment(Constants.TYPE_PROTO_ID_ITEM);
-    if (index >= segment.size) {
+    if (index >= segment.length) {
       return null;
     }
     int offset = segment.offset + (Constants.TYPE_PROTO_ID_ITEM_SIZE * index);
@@ -979,7 +979,7 @@
 
   private DexMethod methodAt(int index) {
     Segment segment = lookupSegment(Constants.TYPE_METHOD_ID_ITEM);
-    if (index >= segment.size) {
+    if (index >= segment.length) {
       return null;
     }
     int offset = segment.offset + (Constants.TYPE_METHOD_ID_ITEM_SIZE * index);
diff --git a/src/main/java/com/android/tools/r8/dex/Segment.java b/src/main/java/com/android/tools/r8/dex/Segment.java
index 1d891e0..1d18347 100644
--- a/src/main/java/com/android/tools/r8/dex/Segment.java
+++ b/src/main/java/com/android/tools/r8/dex/Segment.java
@@ -4,32 +4,28 @@
 package com.android.tools.r8.dex;
 
 public class Segment {
-
-  final int type;
-  final int size;
+  public final int type;
+  public final int length;
   public final int offset;
-  int end;
+  private int end;
 
-  public Segment(int type, int unused, int size, int offset) {
+  public Segment(int type, int unused, int length, int offset) {
     this.type = type;
     assert unused == 0;
-    this.size = size;
+    this.length = length;
     this.offset = offset;
     this.end = -1;
   }
 
-  public int getType() {
-    return type;
-  }
-
-  public int getSize() {
-    return size;
-  }
-
   void setEnd(int end) {
     this.end = end;
   }
 
+  // Returns the byte size of this segment.
+  public int size() {
+    return end - offset;
+  }
+
   public String typeName() {
     switch (type) {
       case Constants.TYPE_HEADER_ITEM:
@@ -74,6 +70,6 @@
   }
 
   public String toString() {
-    return typeName() + " @" + offset + " " + size;
+    return typeName() + " @" + offset + " " + length;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
index 7d83150..03f9470 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java
@@ -82,7 +82,7 @@
     return candidate;
   }
 
-  private DexEncodedMethod doubleInlining(DexEncodedMethod candidate) {
+  private synchronized DexEncodedMethod doubleInlining(DexEncodedMethod candidate) {
     if (!inliner.applyDoubleInlining) {
       if (inliner.doubleInlineeCandidates.containsKey(candidate)) {
         // Both calls can be inlined.
@@ -222,7 +222,7 @@
     return (clazz != null) && (!clazz.hasClassInitializer());
   }
 
-  private boolean isDoubleInliningTarget(DexEncodedMethod candidate) {
+  private synchronized boolean isDoubleInliningTarget(DexEncodedMethod candidate) {
     // 10 is found from measuring.
     return callGraph.hasDoubleCallSite(candidate)
         && candidate.getCode().isDexCode()
diff --git a/src/test/java/com/android/tools/r8/R8CodeCanonicalizationTest.java b/src/test/java/com/android/tools/r8/R8CodeCanonicalizationTest.java
index 8fca2ed..3513290 100644
--- a/src/test/java/com/android/tools/r8/R8CodeCanonicalizationTest.java
+++ b/src/test/java/com/android/tools/r8/R8CodeCanonicalizationTest.java
@@ -24,8 +24,8 @@
   private int readNumberOfCodes(Path file) throws IOException {
     Segment[] segments = DexFileReader.parseMapFrom(file);
     for (Segment segment : segments) {
-      if (segment.getType() == Constants.TYPE_CODE_ITEM) {
-        return segment.getSize();
+      if (segment.type == Constants.TYPE_CODE_ITEM) {
+        return segment.length;
       }
     }
     return 0;
diff --git a/tools/gradle.py b/tools/gradle.py
index f30b3f4..3a309ab 100755
--- a/tools/gradle.py
+++ b/tools/gradle.py
@@ -33,13 +33,16 @@
   else:
     print 'gradle.py: Gradle binary present'
 
-def RunGradle(args):
+def RunGradle(args, throw_on_failure=True):
   EnsureGradle()
   cmd = [GRADLE]
   cmd.extend(args)
   utils.PrintCmd(cmd)
   with utils.ChangedWorkingDirectory(utils.REPO_ROOT):
-    subprocess.check_call(cmd)
+    return_value = subprocess.call(cmd)
+    if throw_on_failure:
+      raise
+    return return_value
 
 def Main():
   RunGradle(sys.argv[1:])
diff --git a/tools/test.py b/tools/test.py
index 49a6f3c..7102207 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -11,14 +11,20 @@
 import gradle
 import optparse
 import sys
+import utils
+import uuid
 
 ALL_ART_VMS = ["default", "7.0.0", "6.0.1", "5.1.1"]
+BUCKET = 'r8-test-results'
 
 def ParseOptions():
   result = optparse.OptionParser()
   result.add_option('--no_internal',
       help='Do not run Google internal tests.',
       default=False, action='store_true')
+  result.add_option('--archive_failures',
+      help='Upload test results to cloud storage on failure.',
+      default=False, action='store_true')
   result.add_option('--only_internal',
       help='Only run Google internal tests.',
       default=False, action='store_true')
@@ -54,6 +60,14 @@
 
   return result.parse_args()
 
+def archive_failures():
+  upload_dir = os.path.join(utils.REPO_ROOT, 'build', 'reports', 'tests')
+  u_dir = uuid.uuid4()
+  destination = 'gs://%s/%s' % (BUCKET, u_dir)
+  utils.upload_html_to_cloud_storage(upload_dir, destination)
+  url = 'http://storage.googleapis.com/%s/%s/index.html' % (BUCKET, u_dir)
+  print 'Test results available at: %s' % url
+
 def Main():
   (options, args) = ParseOptions()
   gradle_args = ['cleanTest', 'test']
@@ -94,7 +108,12 @@
     gradle_args.append('jctfTestsClasses')
   vms_to_test = [options.dex_vm] if options.dex_vm != "all" else ALL_ART_VMS
   for art_vm in vms_to_test:
-    gradle.RunGradle(gradle_args + ['-Pdex_vm=%s' % art_vm])
+    return_code = gradle.RunGradle(gradle_args + ['-Pdex_vm=%s' % art_vm],
+                                   throw_on_failure=False)
+    if return_code != 0:
+      if options.archive_failures:
+        archive_failures()
+      return return_code
 
 if __name__ == '__main__':
   sys.exit(Main())
diff --git a/tools/utils.py b/tools/utils.py
index 8c4f710..fd7212b 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -50,6 +50,13 @@
     if not os.path.isdir(path):
         raise
 
+def upload_html_to_cloud_storage(directory, destination):
+  # Upload and make the content encoding right for viewing directly
+  cmd = ['gsutil.py', 'cp', '-z', 'html', '-a',
+         'public-read', '-R', directory, destination]
+  PrintCmd(cmd)
+  subprocess.check_call(cmd)
+
 class TempDir(object):
  def __init__(self, prefix=''):
    self._temp_dir = None