Sort items in writer threads using full compare sorting.

Bug: 149190785
Bug: 151313715
Bug: 151313617
Change-Id: Iedcc94af2b15afe903d930a6a6a5dbfa9c738815
diff --git a/src/main/java/com/android/tools/r8/DexSplitterHelper.java b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
index 6f6d70f..a9d4644 100644
--- a/src/main/java/com/android/tools/r8/DexSplitterHelper.java
+++ b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
@@ -83,8 +83,6 @@
           getDistribution(app, featureClassMapping, mapper);
       for (Entry<String, LazyLoadedDexApplication.Builder> entry : applications.entrySet()) {
         DexApplication featureApp = entry.getValue().build();
-        // We use the same factory, reset sorting.
-        featureApp.dexItemFactory.resetSortedIndices();
         assert !options.hasMethodsFilter();
 
         // Run d8 optimize to ensure jumbo strings are handled.
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 4961a3e..5223520 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -155,7 +155,6 @@
       System.gc();
     }
     timing = Timing.create("R8", options);
-    options.itemFactory.resetSortedIndices();
   }
 
   /**
diff --git a/src/main/java/com/android/tools/r8/bisect/Bisect.java b/src/main/java/com/android/tools/r8/bisect/Bisect.java
index 29ecba6..0e86dc7 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -88,7 +88,6 @@
         return null;
       }
       state.setPreviousResult(command.apply(app));
-      app.options.itemFactory.resetSortedIndices();
     }
   }
 
diff --git a/src/main/java/com/android/tools/r8/bisect/BisectState.java b/src/main/java/com/android/tools/r8/bisect/BisectState.java
index 5500637..cd3fe0a 100644
--- a/src/main/java/com/android/tools/r8/bisect/BisectState.java
+++ b/src/main/java/com/android/tools/r8/bisect/BisectState.java
@@ -21,7 +21,6 @@
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.util.ArrayList;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 
@@ -324,9 +323,7 @@
 
   private static List<DexProgramClass> getSortedClasses(DexApplication app) {
     List<DexProgramClass> classes = new ArrayList<>(app.classes());
-    app.dexItemFactory.sort(NamingLens.getIdentityLens());
-    classes.sort(Comparator.comparing(DexProgramClass::getType));
-    app.dexItemFactory.resetSortedIndices();
+    classes.sort((a, b) -> a.type.slowCompareTo(b.type, NamingLens.getIdentityLens()));
     return classes;
   }
 
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 1adea89..c4c318c 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -82,10 +82,16 @@
 
   private static class SortAnnotations extends MixedSectionCollection {
 
+    private final NamingLens namingLens;
+
+    public SortAnnotations(NamingLens namingLens) {
+      this.namingLens = namingLens;
+    }
+
     @Override
     public boolean add(DexAnnotationSet dexAnnotationSet) {
       // Annotation sets are sorted by annotation types.
-      dexAnnotationSet.sort();
+      dexAnnotationSet.sort(namingLens);
       return true;
     }
 
@@ -244,6 +250,7 @@
       }
     }
     try {
+      // TODO(b/151313715): Move this to the writer threads.
       insertAttributeAnnotations();
 
       // Generate the dex file contents.
@@ -252,21 +259,12 @@
       if (options.encodeChecksums) {
         encodeChecksums(virtualFiles);
       }
-      // TODO(b/149190785): Only sort the live program!
-      if (appView != null) {
-        appView.appInfo().disableDefinitionForAssert();
-      }
-      namingLens.setIsSortingBeforeWriting(true);
-      application.dexItemFactory.sort(namingLens);
-      namingLens.setIsSortingBeforeWriting(false);
-      if (appView != null) {
-        appView.appInfo().enableDefinitionForAssert();
-      }
       assert markers == null
           || markers.isEmpty()
           || application.dexItemFactory.extractMarkers() != null;
 
-      SortAnnotations sortAnnotations = new SortAnnotations();
+      // TODO(b/151313617): Sorting annotations mutates elements so run single threaded on main.
+      SortAnnotations sortAnnotations = new SortAnnotations(namingLens);
       application.classes().forEach((clazz) -> clazz.addDependencies(sortAnnotations));
 
       for (VirtualFile virtualFile : virtualFiles) {
@@ -297,7 +295,7 @@
                     }
                   }
                   ObjectToOffsetMapping objectMapping =
-                      virtualFile.computeMapping(application, initClassLens);
+                      virtualFile.computeMapping(application, namingLens, initClassLens);
                   MethodToCodeObjectMapping codeMapping =
                       rewriteCodeWithJumboStrings(
                           objectMapping, virtualFile.classes(), application);
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 561e18f..ffae5aa 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -41,7 +41,6 @@
 import com.android.tools.r8.graph.IndexedDexItem;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
-import com.android.tools.r8.graph.PresortedComparable;
 import com.android.tools.r8.graph.ProgramClassVisitor;
 import com.android.tools.r8.logging.Log;
 import com.android.tools.r8.naming.ClassNameMapper;
@@ -59,6 +58,7 @@
 import it.unimi.dsi.fastutil.objects.Reference2IntMap;
 import java.security.MessageDigest;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -94,6 +94,7 @@
   private final DexOutputBuffer dest;
   private final MixedSectionOffsets mixedSectionOffsets;
   private final CodeToKeep desugaredLibraryCodeToKeep;
+  private final Map<DexProgramClass, DexEncodedArray> staticFieldValues = new IdentityHashMap<>();
 
   public FileWriter(
       ByteBufferProvider provider,
@@ -118,10 +119,11 @@
     if (Log.ENABLED) {
       Log.verbose(FileWriter.class, "Writing encoded annotation @ %08x", dest.position());
     }
+    List<DexAnnotationElement> elements = new ArrayList<>(Arrays.asList(annotation.elements));
+    elements.sort((a, b) -> a.name.slowCompareTo(b.name, mapping.getNamingLens()));
     dest.putUleb128(mapping.getOffsetFor(annotation.type));
-    dest.putUleb128(annotation.elements.length);
-    assert PresortedComparable.isSorted(annotation.elements, (element) -> element.name);
-    for (DexAnnotationElement element : annotation.elements) {
+    dest.putUleb128(elements.size());
+    for (DexAnnotationElement element : elements) {
       dest.putUleb128(mapping.getOffsetFor(element.name));
       element.value.writeTo(dest, mapping);
     }
@@ -132,8 +134,6 @@
     new ProgramClassDependencyCollector(application, mapping.getClasses())
         .run(mapping.getClasses());
 
-    // Ensure everything is sorted.
-    assert mixedSectionOffsets.getClassesWithData().stream().allMatch(DexProgramClass::isSorted);
     // Add the static values for all fields now that we have committed to their sorting.
     mixedSectionOffsets.getClassesWithData().forEach(this::addStaticFieldValues);
 
@@ -465,7 +465,7 @@
     dest.putInt(mixedSectionOffsets.getOffsetForAnnotationsDirectory(clazz));
     dest.putInt(
         clazz.hasMethodsOrFields() ? mixedSectionOffsets.getOffsetFor(clazz) : Constants.NO_OFFSET);
-    dest.putInt(mixedSectionOffsets.getOffsetFor(clazz.getStaticValues()));
+    dest.putInt(mixedSectionOffsets.getOffsetFor(staticFieldValues.get(clazz)));
   }
 
   private void writeDebugItem(DexDebugInfo debugInfo) {
@@ -551,14 +551,14 @@
   }
 
   private void writeAnnotationSet(DexAnnotationSet set) {
-    assert PresortedComparable.isSorted(set.annotations, (item) -> item.annotation.type)
-        : "Unsorted annotation set: " + set.toSourceString();
     mixedSectionOffsets.setOffsetFor(set, dest.align(4));
     if (Log.ENABLED) {
       Log.verbose(getClass(), "Writing AnnotationSet @ 0x%08x.", dest.position());
     }
-    dest.putInt(set.annotations.length);
-    for (DexAnnotation annotation : set.annotations) {
+    List<DexAnnotation> annotations = new ArrayList<>(Arrays.asList(set.annotations));
+    annotations.sort((a, b) -> a.annotation.type.slowCompareTo(b.annotation.type, namingLens));
+    dest.putInt(annotations.size());
+    for (DexAnnotation annotation : annotations) {
       dest.putInt(mixedSectionOffsets.getOffsetFor(annotation));
     }
   }
@@ -588,9 +588,11 @@
   private void writeAnnotationDirectory(DexAnnotationDirectory annotationDirectory) {
     mixedSectionOffsets.setOffsetForAnnotationsDirectory(annotationDirectory, dest.align(4));
     dest.putInt(mixedSectionOffsets.getOffsetFor(annotationDirectory.getClazzAnnotations()));
-    List<DexEncodedMethod> methodAnnotations = annotationDirectory.getMethodAnnotations();
-    List<DexEncodedMethod> parameterAnnotations = annotationDirectory.getParameterAnnotations();
-    List<DexEncodedField> fieldAnnotations = annotationDirectory.getFieldAnnotations();
+    List<DexEncodedMethod> methodAnnotations =
+        annotationDirectory.sortMethodAnnotations(namingLens);
+    List<DexEncodedMethod> parameterAnnotations =
+        annotationDirectory.sortParameterAnnotations(namingLens);
+    List<DexEncodedField> fieldAnnotations = annotationDirectory.sortFieldAnnotations(namingLens);
     dest.putInt(fieldAnnotations.size());
     dest.putInt(methodAnnotations.size());
     dest.putInt(parameterAnnotations.size());
@@ -602,8 +604,9 @@
         item -> mixedSectionOffsets.getOffsetFor(item.parameterAnnotationsList));
   }
 
-  private void writeEncodedFields(List<DexEncodedField> fields) {
-    assert PresortedComparable.isSorted(fields);
+  private void writeEncodedFields(List<DexEncodedField> unsortedFields) {
+    List<DexEncodedField> fields = new ArrayList<>(unsortedFields);
+    fields.sort((a, b) -> a.field.slowCompareTo(b.field, namingLens));
     int currentOffset = 0;
     for (DexEncodedField field : fields) {
       assert field.validateDexValue(application.dexItemFactory);
@@ -616,8 +619,10 @@
     }
   }
 
-  private void writeEncodedMethods(List<DexEncodedMethod> methods, boolean isSharedSynthetic) {
-    assert PresortedComparable.isSorted(methods);
+  private void writeEncodedMethods(
+      List<DexEncodedMethod> unsortedMethods, boolean isSharedSynthetic) {
+    List<DexEncodedMethod> methods = new ArrayList<>(unsortedMethods);
+    methods.sort((a, b) -> a.method.slowCompareTo(b.method, namingLens));
     int currentOffset = 0;
     for (DexEncodedMethod method : methods) {
       int nextOffset = mapping.getOffsetFor(method.method);
@@ -658,12 +663,12 @@
   }
 
   private void addStaticFieldValues(DexProgramClass clazz) {
-    clazz.computeStaticValues();
     // We have collected the individual components of this array due to the data stored in
     // DexEncodedField#staticValues. However, we have to collect the DexEncodedArray itself
     // here.
-    DexEncodedArray staticValues = clazz.getStaticValues();
+    DexEncodedArray staticValues = clazz.computeStaticValuesArray(namingLens);
     if (staticValues != null) {
+      staticFieldValues.put(clazz, staticValues);
       mixedSectionOffsets.add(staticValues);
     }
   }
diff --git a/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java b/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
index 2936d80..e05af85 100644
--- a/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
+++ b/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
@@ -284,7 +284,7 @@
         instruction.setOffset(orignalOffset + offsetDelta);
         if (instruction instanceof ConstString) {
           ConstString string = (ConstString) instruction;
-          if (string.getString().compareTo(firstJumboString) >= 0) {
+          if (string.getString().slowCompareTo(firstJumboString) >= 0) {
             ConstStringJumbo jumboString = new ConstStringJumbo(string.AA, string.getString());
             jumboString.setOffset(string.getOffset());
             offsetDelta++;
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index 1909f87..a9ff477 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -182,10 +182,12 @@
   }
 
   public ObjectToOffsetMapping computeMapping(
-      DexApplication application, InitClassLens initClassLens) {
+      DexApplication application, NamingLens namingLens, InitClassLens initClassLens) {
     assert transaction.isEmpty();
     return new ObjectToOffsetMapping(
         application,
+        namingLens,
+        initClassLens,
         indexedItems.classes,
         indexedItems.protos,
         indexedItems.types,
@@ -193,8 +195,7 @@
         indexedItems.fields,
         indexedItems.strings,
         indexedItems.callSites,
-        indexedItems.methodHandles,
-        initClassLens);
+        indexedItems.methodHandles);
   }
 
   void addClass(DexProgramClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index 640b7a1..2ddba3f 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -705,10 +705,4 @@
         entry.getKey(),
         entry.getValue());
   }
-
-  // TODO(b/149190785): Remove once fixed.
-  public void enableDefinitionForAssert() {}
-
-  // TODO(b/149190785): Remove once fixed.
-  public void disableDefinitionForAssert() {}
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
index 2d0667b..a6b7824 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
@@ -6,10 +6,9 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.MixedSectionCollection;
 import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.utils.OrderedMergingIterator;
+import com.android.tools.r8.naming.NamingLens;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.function.Function;
 
 public class DexAnnotationDirectory extends DexItem {
 
@@ -22,28 +21,21 @@
   public DexAnnotationDirectory(DexProgramClass clazz) {
     this.clazz = clazz;
     this.classHasOnlyInternalizableAnnotations = clazz.hasOnlyInternalizableAnnotations();
-    assert isSorted(clazz.directMethods());
-    assert isSorted(clazz.virtualMethods());
-    OrderedMergingIterator<DexEncodedMethod, DexMethod> methods =
-        new OrderedMergingIterator<>(clazz.directMethods(), clazz.virtualMethods());
     methodAnnotations = new ArrayList<>();
     parameterAnnotations = new ArrayList<>();
-    while (methods.hasNext()) {
-      DexEncodedMethod method = methods.next();
-      if (!method.annotations().isEmpty()) {
-        methodAnnotations.add(method);
-      }
-      if (!method.parameterAnnotationsList.isEmpty()) {
-        parameterAnnotations.add(method);
-      }
-    }
-    assert isSorted(clazz.staticFields());
-    assert isSorted(clazz.instanceFields());
-    OrderedMergingIterator<DexEncodedField, DexField> fields =
-        new OrderedMergingIterator<>(clazz.staticFields(), clazz.instanceFields());
     fieldAnnotations = new ArrayList<>();
-    while (fields.hasNext()) {
-      DexEncodedField field = fields.next();
+    clazz
+        .getMethodCollection()
+        .forEachMethod(
+            method -> {
+              if (!method.annotations().isEmpty()) {
+                methodAnnotations.add(method);
+              }
+              if (!method.parameterAnnotationsList.isEmpty()) {
+                parameterAnnotations.add(method);
+              }
+            });
+    for (DexEncodedField field : clazz.fields()) {
       if (!field.annotations().isEmpty()) {
         fieldAnnotations.add(field);
       }
@@ -54,15 +46,18 @@
     return clazz.annotations();
   }
 
-  public List<DexEncodedMethod> getMethodAnnotations() {
+  public List<DexEncodedMethod> sortMethodAnnotations(NamingLens namingLens) {
+    methodAnnotations.sort((a, b) -> a.method.slowCompareTo(b.method, namingLens));
     return methodAnnotations;
   }
 
-  public List<DexEncodedMethod> getParameterAnnotations() {
+  public List<DexEncodedMethod> sortParameterAnnotations(NamingLens namingLens) {
+    parameterAnnotations.sort((a, b) -> a.method.slowCompareTo(b.method, namingLens));
     return parameterAnnotations;
   }
 
-  public List<DexEncodedField> getFieldAnnotations() {
+  public List<DexEncodedField> sortFieldAnnotations(NamingLens namingLens) {
+    fieldAnnotations.sort((a, b) -> a.field.slowCompareTo(b.field, namingLens));
     return fieldAnnotations;
   }
 
@@ -106,22 +101,4 @@
   public void collectMixedSectionItems(MixedSectionCollection collection) {
     throw new Unreachable();
   }
-
-  private static <D extends DexEncodedMember<D, R>, R extends DexMember<D, R>> boolean isSorted(
-      List<D> items) {
-    return isSorted(items, DexEncodedMember::toReference);
-  }
-
-  private static <S, T extends Comparable<T>> boolean isSorted(
-      List<S> items, Function<S, T> getter) {
-    T current = null;
-    for (S item : items) {
-      T next = getter.apply(item);
-      if (current != null && current.compareTo(next) >= 0) {
-        return false;
-      }
-      current = next;
-    }
-    return true;
-  }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
index dd24ed6..7371902 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationSet.java
@@ -5,10 +5,10 @@
 
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.google.common.collect.Sets;
 import java.util.Arrays;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Consumer;
@@ -93,12 +93,13 @@
     return annotations.length == 0;
   }
 
-  public void sort() {
+  public void sort(NamingLens namingLens) {
     if (sorted != UNSORTED) {
       assert sorted == sortedHashCode();
       return;
     }
-    Arrays.sort(annotations, Comparator.comparing(a -> a.annotation.type));
+    Arrays.sort(
+        annotations, (a, b) -> a.annotation.type.slowCompareTo(b.annotation.type, namingLens));
     for (DexAnnotation annotation : annotations) {
       annotation.annotation.sort();
     }
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
index c0c2d6e..f5c5272 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
@@ -63,7 +63,7 @@
       assert sorted == sortedHashCode();
       return;
     }
-    Arrays.sort(elements, (a, b) -> a.name.compareTo(b.name));
+    Arrays.sort(elements, (a, b) -> a.name.slowCompareTo(b.name));
     for (DexAnnotationElement element : elements) {
       element.value.sort();
     }
diff --git a/src/main/java/com/android/tools/r8/graph/DexField.java b/src/main/java/com/android/tools/r8/graph/DexField.java
index 02cb985..d10a2c8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -72,11 +72,6 @@
   }
 
   @Override
-  public int compareTo(DexField other) {
-    return sortedCompareTo(other.getSortedIndex());
-  }
-
-  @Override
   public int slowCompareTo(DexField other) {
     int result = holder.slowCompareTo(other.holder);
     if (result != 0) {
@@ -103,19 +98,6 @@
   }
 
   @Override
-  public int layeredCompareTo(DexField other, NamingLens namingLens) {
-    int result = holder.compareTo(other.holder);
-    if (result != 0) {
-      return result;
-    }
-    result = namingLens.lookupName(this).compareTo(namingLens.lookupName(other));
-    if (result != 0) {
-      return result;
-    }
-    return type.compareTo(other.type);
-  }
-
-  @Override
   public boolean match(DexField field) {
     return field.name == name && field.type == type;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index fe33ab9..bfaf19c 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -27,7 +27,6 @@
 import com.android.tools.r8.ir.code.Position;
 import com.android.tools.r8.ir.code.Value;
 import com.android.tools.r8.kotlin.Kotlin;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.ArrayUtils;
 import com.android.tools.r8.utils.LRUCacheTable;
 import com.android.tools.r8.utils.Pair;
@@ -44,7 +43,6 @@
 import it.unimi.dsi.fastutil.ints.Int2ReferenceOpenHashMap;
 import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
@@ -1725,39 +1723,6 @@
         );
   }
 
-  private static <S extends PresortedComparable<S>> void assignSortedIndices(Collection<S> items,
-      NamingLens namingLens) {
-    List<S> sorted = new ArrayList<>(items);
-    sorted.sort((a, b) -> a.layeredCompareTo(b, namingLens));
-    int i = 0;
-    for (S value : sorted) {
-      value.setSortedIndex(i++);
-    }
-  }
-
-  synchronized public void sort(NamingLens namingLens) {
-    assert !sorted;
-    assignSortedIndices(strings.values(), namingLens);
-    assignSortedIndices(types.values(), namingLens);
-    assignSortedIndices(fields.values(), namingLens);
-    assignSortedIndices(protos.values(), namingLens);
-    assignSortedIndices(methods.values(), namingLens);
-    sorted = true;
-  }
-
-  synchronized public void resetSortedIndices() {
-    if (!sorted) {
-      return;
-    }
-    // Only used for asserting that we don't use the sorted index after we build the graph.
-    strings.values().forEach(IndexedDexItem::resetSortedIndex);
-    types.values().forEach(IndexedDexItem::resetSortedIndex);
-    fields.values().forEach(IndexedDexItem::resetSortedIndex);
-    protos.values().forEach(IndexedDexItem::resetSortedIndex);
-    methods.values().forEach(IndexedDexItem::resetSortedIndex);
-    sorted = false;
-  }
-
   synchronized public void forAllTypes(Consumer<DexType> f) {
     new ArrayList<>(types.values()).forEach(f);
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index a29eb31..b15ee67 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -102,11 +102,6 @@
   }
 
   @Override
-  public int compareTo(DexMethod other) {
-    return sortedCompareTo(other.getSortedIndex());
-  }
-
-  @Override
   public int slowCompareTo(DexMethod other) {
     int result = holder.slowCompareTo(other.holder);
     if (result != 0) {
@@ -133,19 +128,6 @@
   }
 
   @Override
-  public int layeredCompareTo(DexMethod other, NamingLens namingLens) {
-    int result = holder.compareTo(other.holder);
-    if (result != 0) {
-      return result;
-    }
-    result = namingLens.lookupName(this).compareTo(namingLens.lookupName(other));
-    if (result != 0) {
-      return result;
-    }
-    return proto.compareTo(other.proto);
-  }
-
-  @Override
   public boolean match(DexMethod method) {
     return method.name == name && method.proto == proto;
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
index fbe8a9f..a4be032 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
@@ -339,25 +339,6 @@
     return result;
   }
 
-  @Override
-  public int layeredCompareTo(DexMethodHandle other, NamingLens namingLens) {
-    int result = type.getValue() - other.type.getValue();
-    if (result == 0) {
-      if (isFieldHandle()) {
-        result = asField().layeredCompareTo(other.asField(), namingLens);
-      } else {
-        assert isMethodHandle();
-        result = asMethod().layeredCompareTo(other.asMethod(), namingLens);
-      }
-    }
-    return result;
-  }
-
-  @Override
-  public int compareTo(DexMethodHandle other) {
-    return slowCompareTo(other);
-  }
-
   public Handle toAsmHandle(NamingLens lens) {
     String owner;
     String name;
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 35f209a..221a19e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -9,13 +9,13 @@
 import com.android.tools.r8.dex.MixedSectionCollection;
 import com.android.tools.r8.errors.CompilationError;
 import com.android.tools.r8.kotlin.KotlinInfo;
+import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.shaking.AppInfoWithLiveness;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
@@ -34,7 +34,6 @@
       new DexEncodedArray(DexValue.EMPTY_ARRAY);
 
   private final ProgramResource.Kind originKind;
-  private DexEncodedArray staticValues = SENTINEL_NOT_YET_COMPUTED;
   private final Collection<DexProgramClass> synthesizedFrom;
   private int initialClassFileVersion = -1;
   private KotlinInfo kotlinInfo = null;
@@ -193,15 +192,9 @@
     // We only have a class data item if there are methods or fields.
     if (hasMethodsOrFields()) {
       collector.add(this);
-
-      // The ordering of methods and fields may not be deterministic due to concurrency
-      // (see b/116027780).
-      sortMembers();
-      synchronized (methodCollection) {
-        methodCollection.forEachMethod(m -> m.collectMixedSectionItems(collector));
-      }
-      synchronizedCollectAll(collector, staticFields);
-      synchronizedCollectAll(collector, instanceFields);
+      methodCollection.forEachMethod(m -> m.collectMixedSectionItems(collector));
+      collectAll(collector, staticFields);
+      collectAll(collector, instanceFields);
     }
     annotations().collectMixedSectionItems(collector);
     if (interfaces != null) {
@@ -209,13 +202,6 @@
     }
   }
 
-  private static <T extends DexItem> void synchronizedCollectAll(MixedSectionCollection collection,
-      T[] items) {
-    synchronized (items) {
-      collectAll(collection, items);
-    }
-  }
-
   @Override
   public String toString() {
     return type.toString();
@@ -320,51 +306,37 @@
     }
   }
 
-  public void computeStaticValues() {
-    // It does not actually hurt to compute this multiple times. So racing on staticValues is OK.
-    if (staticValues == SENTINEL_NOT_YET_COMPUTED) {
-      synchronized (staticFields) {
-        assert PresortedComparable.isSorted(Arrays.asList(staticFields));
-        DexEncodedField[] fields = staticFields;
-        int length = 0;
-        List<DexValue> values = new ArrayList<>(fields.length);
-        for (int i = 0; i < fields.length; i++) {
-          DexEncodedField field = fields[i];
-          DexValue staticValue = field.getStaticValue();
-          assert staticValue != null;
-          values.add(staticValue);
-          if (!staticValue.isDefault(field.field.type)) {
-            length = i + 1;
-          }
-        }
-        staticValues =
-            length > 0
-                ? new DexEncodedArray(values.subList(0, length).toArray(DexValue.EMPTY_ARRAY))
-                : null;
-      }
-    }
-  }
-
-  public boolean isSorted() {
-    return methodCollection.isSorted() && isSorted(staticFields) && isSorted(instanceFields);
-  }
-
-  private static <D extends DexEncodedMember<D, R>, R extends DexMember<D, R>> boolean isSorted(
-      D[] items) {
-    synchronized (items) {
-      D[] sorted = items.clone();
-      Arrays.sort(sorted, Comparator.comparing(DexEncodedMember::toReference));
-      return Arrays.equals(items, sorted);
-    }
-  }
-
-  public DexEncodedArray getStaticValues() {
-    // The sentinel value is left over for classes that actually have no fields.
-    if (staticValues == SENTINEL_NOT_YET_COMPUTED) {
-      assert !hasMethodsOrFields();
+  public DexEncodedArray computeStaticValuesArray(NamingLens namingLens) {
+    // Fast path to avoid sorting and collection allocation when no non-default values exist.
+    if (!hasNonDefaultStaticFieldValues()) {
       return null;
     }
-    return staticValues;
+    DexEncodedField[] fields = staticFields;
+    Arrays.sort(fields, (a, b) -> a.field.slowCompareTo(b.field, namingLens));
+    int length = 0;
+    List<DexValue> values = new ArrayList<>(fields.length);
+    for (int i = 0; i < fields.length; i++) {
+      DexEncodedField field = fields[i];
+      DexValue staticValue = field.getStaticValue();
+      assert staticValue != null;
+      values.add(staticValue);
+      if (!staticValue.isDefault(field.field.type)) {
+        length = i + 1;
+      }
+    }
+    return length > 0
+        ? new DexEncodedArray(values.subList(0, length).toArray(DexValue.EMPTY_ARRAY))
+        : null;
+  }
+
+  private boolean hasNonDefaultStaticFieldValues() {
+    for (DexEncodedField field : staticFields) {
+      DexValue value = field.getStaticValue();
+      if (value != null && !value.isDefault(field.field.type)) {
+        return true;
+      }
+    }
+    return false;
   }
 
   public void addMethod(DexEncodedMethod method) {
@@ -379,18 +351,6 @@
     methodCollection.addDirectMethod(directMethod);
   }
 
-  public void sortMembers() {
-    sortEncodedFields(staticFields);
-    sortEncodedFields(instanceFields);
-    methodCollection.sort();
-  }
-
-  private void sortEncodedFields(DexEncodedField[] fields) {
-    synchronized (fields) {
-      Arrays.sort(fields, Comparator.comparing(a -> a.field));
-    }
-  }
-
   @Override
   public DexProgramClass get() {
     return this;
diff --git a/src/main/java/com/android/tools/r8/graph/DexProto.java b/src/main/java/com/android/tools/r8/graph/DexProto.java
index 43d6a29..a9a15f3 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProto.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProto.java
@@ -63,11 +63,6 @@
   }
 
   @Override
-  public int compareTo(DexProto other) {
-    return sortedCompareTo(other.getSortedIndex());
-  }
-
-  @Override
   public int slowCompareTo(DexProto other) {
     int result = returnType.slowCompareTo(other.returnType);
     if (result == 0) {
@@ -86,15 +81,6 @@
   }
 
   @Override
-  public int layeredCompareTo(DexProto other, NamingLens namingLens) {
-    int result = returnType.compareTo(other.returnType);
-    if (result == 0) {
-      result = parameters.compareTo(other.parameters);
-    }
-    return result;
-  }
-
-  @Override
   public String toSmaliString() {
     return toDescriptorString();
   }
diff --git a/src/main/java/com/android/tools/r8/graph/DexString.java b/src/main/java/com/android/tools/r8/graph/DexString.java
index f3a829c..03303f6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexString.java
+++ b/src/main/java/com/android/tools/r8/graph/DexString.java
@@ -251,11 +251,6 @@
   }
 
   @Override
-  public int compareTo(DexString other) {
-    return sortedCompareTo(other.getSortedIndex());
-  }
-
-  @Override
   public int slowCompareTo(DexString other) {
     // Compare the bytes, as comparing UTF-8 encoded strings as strings of unsigned bytes gives
     // the same result as comparing the corresponding Unicode strings lexicographically by
@@ -294,12 +289,6 @@
     return slowCompareTo(other);
   }
 
-  @Override
-  public int layeredCompareTo(DexString other, NamingLens lens) {
-    // Strings have no subparts that are already sorted.
-    return slowCompareTo(other);
-  }
-
   private static boolean isValidClassDescriptor(String string) {
     if (string.length() < 3
         || string.charAt(0) != 'L'
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index c046e6a..4b8c6d4 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -175,11 +175,6 @@
   }
 
   @Override
-  public int compareTo(DexType other) {
-    return sortedCompareTo(other.getSortedIndex());
-  }
-
-  @Override
   public int slowCompareTo(DexType other) {
     return descriptor.slowCompareTo(other.descriptor);
   }
@@ -188,14 +183,7 @@
   public int slowCompareTo(DexType other, NamingLens namingLens) {
     DexString thisDescriptor = namingLens.lookupDescriptor(this);
     DexString otherDescriptor = namingLens.lookupDescriptor(other);
-    return thisDescriptor.slowCompareTo(otherDescriptor);
-  }
-
-  @Override
-  public int layeredCompareTo(DexType other, NamingLens namingLens) {
-    DexString thisDescriptor = namingLens.lookupDescriptor(this);
-    DexString otherDescriptor = namingLens.lookupDescriptor(other);
-    return thisDescriptor.compareTo(otherDescriptor);
+    return thisDescriptor.slowCompareTo(otherDescriptor, namingLens);
   }
 
   public boolean isPrimitiveType() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexTypeList.java b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
index a124bc4..58b6afd 100644
--- a/src/main/java/com/android/tools/r8/graph/DexTypeList.java
+++ b/src/main/java/com/android/tools/r8/graph/DexTypeList.java
@@ -9,7 +9,7 @@
 import com.android.tools.r8.naming.NamingLens;
 import java.util.Arrays;
 
-public class DexTypeList extends DexItem implements Comparable<DexTypeList> {
+public class DexTypeList extends DexItem {
 
   private static final DexTypeList theEmptyTypeList = new DexTypeList();
 
@@ -75,23 +75,6 @@
     return builder.toString();
   }
 
-  @Override
-  public int compareTo(DexTypeList other) {
-    for (int i = 0; i <= Math.min(values.length, other.values.length); i++) {
-      if (i == values.length) {
-        return i == other.values.length ? 0 : -1;
-      } else if (i == other.values.length) {
-        return 1;
-      } else {
-        int result = values[i].compareTo(other.values[i]);
-        if (result != 0) {
-          return result;
-        }
-      }
-    }
-    throw new Unreachable();
-  }
-
   public int slowCompareTo(DexTypeList other) {
     for (int i = 0; i <= Math.min(values.length, other.values.length); i++) {
       if (i == values.length) {
diff --git a/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java b/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java
index 68a0e5d..0c115e1 100644
--- a/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java
+++ b/src/main/java/com/android/tools/r8/graph/IndexedDexItem.java
@@ -6,13 +6,8 @@
 import com.android.tools.r8.dex.IndexedItemCollection;
 import com.android.tools.r8.dex.MixedSectionCollection;
 
-/**
- * Subset of dex items that are referenced by some table index.
- */
-public abstract class IndexedDexItem extends CachedHashValueDexItem implements Presorted {
-
-  private static final int SORTED_INDEX_UNKNOWN = -1;
-  private int sortedIndex = SORTED_INDEX_UNKNOWN; // assigned globally after reading.
+/** Subset of dex items that are referenced by some table index. */
+public abstract class IndexedDexItem extends CachedHashValueDexItem {
 
   @Override
   public abstract void collectIndexedItems(IndexedItemCollection indexedItems,
@@ -29,32 +24,7 @@
   // Partial implementation of PresortedComparable.
 
   @Override
-  final public void setSortedIndex(int sortedIndex) {
-    assert sortedIndex > SORTED_INDEX_UNKNOWN;
-    assert this.sortedIndex == SORTED_INDEX_UNKNOWN;
-    this.sortedIndex = sortedIndex;
-  }
-
-  @Override
-  final public int getSortedIndex() {
-    return sortedIndex;
-  }
-
-  @Override
-  final public int sortedCompareTo(int other) {
-    assert sortedIndex > SORTED_INDEX_UNKNOWN
-        : "sortedIndex <= SORTED_INDEX_UKNOWN for: " + this.toString();
-    assert other > SORTED_INDEX_UNKNOWN : "other < SORTED_INDEX_UKNOWN for: " + this.toString();
-    return Integer.compare(sortedIndex, other);
-  }
-
-  @Override
   public void flushCachedValues() {
     super.flushCachedValues();
-    resetSortedIndex();
-  }
-
-  public void resetSortedIndex() {
-    sortedIndex = SORTED_INDEX_UNKNOWN;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
index da5ebe9..7800d81a 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
@@ -12,7 +12,6 @@
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Function;
@@ -242,25 +241,6 @@
     return true;
   }
 
-  synchronized boolean isSorted() {
-    return isSorted(virtualMethods) && isSorted(directMethods);
-  }
-
-  private static boolean isSorted(DexEncodedMethod[] items) {
-    DexEncodedMethod[] sorted = items.clone();
-    Arrays.sort(sorted, Comparator.comparing(DexEncodedMember::toReference));
-    return Arrays.equals(items, sorted);
-  }
-
-  synchronized void sort() {
-    synchronized (virtualMethods) {
-      Arrays.sort(virtualMethods, Comparator.comparing(a -> a.method));
-    }
-    synchronized (directMethods) {
-      Arrays.sort(directMethods, Comparator.comparing(a -> a.method));
-    }
-  }
-
   public DexEncodedMethod replaceDirectMethod(
       DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) {
     for (int i = 0; i < directMethods.length; i++) {
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollection.java b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
index 62a4233..a4f3d5a 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
@@ -186,14 +186,6 @@
         .shouldBreak();
   }
 
-  public boolean isSorted() {
-    return backing.isSorted();
-  }
-
-  public void sort() {
-    backing.sort();
-  }
-
   public boolean verify() {
     forEachMethod(
         method -> {
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
index 828ae4f..33f3b90 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
@@ -5,14 +5,16 @@
 
 import com.android.tools.r8.dex.Constants;
 import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.naming.NamingLens;
 import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
 import it.unimi.dsi.fastutil.objects.Reference2IntMap;
 import it.unimi.dsi.fastutil.objects.Reference2IntMap.Entry;
 import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Comparator;
 import java.util.List;
-import java.util.Map;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
 
@@ -21,20 +23,25 @@
   private final static int NOT_FOUND = -1;
   private final static int NOT_SET = -2;
 
-  private final DexProgramClass[] classes;
-  private final Reference2IntMap<DexProto> protos;
-  private final Reference2IntMap<DexType> types;
-  private final Reference2IntMap<DexMethod> methods;
-  private final Reference2IntMap<DexField> fields;
-  private final Reference2IntMap<DexString> strings;
-  private final Reference2IntMap<DexCallSite> callSites;
-  private final Reference2IntMap<DexMethodHandle> methodHandles;
+  private final NamingLens namingLens;
   private final InitClassLens initClassLens;
 
+  // Sorted collection of objects mapped to their offsets.
+  private final DexProgramClass[] classes;
+  private final Reference2IntLinkedOpenHashMap<DexProto> protos;
+  private final Reference2IntLinkedOpenHashMap<DexType> types;
+  private final Reference2IntLinkedOpenHashMap<DexMethod> methods;
+  private final Reference2IntLinkedOpenHashMap<DexField> fields;
+  private final Reference2IntLinkedOpenHashMap<DexString> strings;
+  private final Reference2IntLinkedOpenHashMap<DexCallSite> callSites;
+  private final Reference2IntLinkedOpenHashMap<DexMethodHandle> methodHandles;
+
   private DexString firstJumboString;
 
   public ObjectToOffsetMapping(
       DexApplication application,
+      NamingLens namingLens,
+      InitClassLens initClassLens,
       Collection<DexProgramClass> classes,
       Collection<DexProto> protos,
       Collection<DexType> types,
@@ -42,8 +49,7 @@
       Collection<DexField> fields,
       Collection<DexString> strings,
       Collection<DexCallSite> callSites,
-      Collection<DexMethodHandle> methodHandles,
-      InitClassLens initClassLens) {
+      Collection<DexMethodHandle> methodHandles) {
     assert application != null;
     assert classes != null;
     assert protos != null;
@@ -54,16 +60,20 @@
     assert callSites != null;
     assert methodHandles != null;
     assert initClassLens != null;
-
-    this.classes = sortClasses(application, classes);
-    this.protos = createMap(protos, this::failOnOverflow);
-    this.types = createMap(types, this::failOnOverflow);
-    this.methods = createMap(methods, this::failOnOverflow);
-    this.fields = createMap(fields, this::failOnOverflow);
-    this.strings = createMap(strings, this::setFirstJumboString);
-    this.callSites = createMap(callSites, this::failOnOverflow);
-    this.methodHandles = createMap(methodHandles, this::failOnOverflow);
+    this.namingLens = namingLens;
     this.initClassLens = initClassLens;
+    this.classes = sortClasses(application, classes, namingLens);
+    this.protos = createSortedMap(protos, compare(namingLens), this::failOnOverflow);
+    this.types = createSortedMap(types, compare(namingLens), this::failOnOverflow);
+    this.methods = createSortedMap(methods, compare(namingLens), this::failOnOverflow);
+    this.fields = createSortedMap(fields, compare(namingLens), this::failOnOverflow);
+    this.strings = createSortedMap(strings, compare(namingLens), this::setFirstJumboString);
+    this.callSites = createSortedMap(callSites, DexCallSite::compareTo, this::failOnOverflow);
+    this.methodHandles = createSortedMap(methodHandles, compare(namingLens), this::failOnOverflow);
+  }
+
+  private static <T extends PresortedComparable<T>> Comparator<T> compare(NamingLens namingLens) {
+    return (a, b) -> a.slowCompareTo(b, namingLens);
   }
 
   private void setFirstJumboString(DexString string) {
@@ -75,14 +85,16 @@
     throw new CompilationError("Index overflow for " + item.getClass());
   }
 
-  private <T extends IndexedDexItem> Reference2IntMap<T> createMap(Collection<T> items,
-      Consumer<T> onUInt16Overflow) {
+  private <T> Reference2IntLinkedOpenHashMap<T> createSortedMap(
+      Collection<T> items, Comparator<T> comparator, Consumer<T> onUInt16Overflow) {
     if (items.isEmpty()) {
       return null;
     }
-    Reference2IntMap<T> map = new Reference2IntLinkedOpenHashMap<>(items.size());
+    // Sort items and compute the offset mapping for each in sorted order.
+    ArrayList<T> sorted = new ArrayList<>(items);
+    sorted.sort(comparator);
+    Reference2IntLinkedOpenHashMap<T> map = new Reference2IntLinkedOpenHashMap<>(items.size());
     map.defaultReturnValue(NOT_FOUND);
-    Collection<T> sorted = items.stream().sorted().collect(Collectors.toList());
     int index = 0;
     for (T item : sorted) {
       if (index == Constants.U16BIT_MAX + 1) {
@@ -140,26 +152,30 @@
   }
 
   private static DexProgramClass[] sortClasses(
-      DexApplication application, Collection<DexProgramClass> classes) {
+      DexApplication application, Collection<DexProgramClass> classes, NamingLens namingLens) {
     // Collect classes in subtyping order, based on a sorted list of classes to start with.
     ProgramClassDepthsMemoized classDepths = new ProgramClassDepthsMemoized(application);
     List<DexProgramClass> sortedClasses =
-        classes
-            .stream()
+        classes.stream()
             .sorted(
                 (x, y) -> {
                   int dx = classDepths.getDepth(x);
                   int dy = classDepths.getDepth(y);
-                  return dx != dy ? dx - dy : x.type.compareTo(y.type);
+                  return dx != dy ? dx - dy : x.type.slowCompareTo(y.type, namingLens);
                 })
             .collect(Collectors.toList());
     return sortedClasses.toArray(DexProgramClass.EMPTY_ARRAY);
   }
 
-  private static <T> Collection<T> keysOrEmpty(Map<T, ?> map) {
+  private static <T> Collection<T> keysOrEmpty(Reference2IntLinkedOpenHashMap<T> map) {
+    // The key-set is deterministic (linked) and inserted in sorted order.
     return map == null ? Collections.emptyList() : map.keySet();
   }
 
+  public NamingLens getNamingLens() {
+    return namingLens;
+  }
+
   public Collection<DexMethod> getMethods() {
     return keysOrEmpty(methods);
   }
diff --git a/src/main/java/com/android/tools/r8/graph/Presorted.java b/src/main/java/com/android/tools/r8/graph/Presorted.java
deleted file mode 100644
index 475da13..0000000
--- a/src/main/java/com/android/tools/r8/graph/Presorted.java
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.graph;
-
-/**
- * Interface for capturing presorted behavior for Dex items.
- */
-public interface Presorted {
-
-  void setSortedIndex(int sortedIndex);
-
-  int getSortedIndex();
-
-  int sortedCompareTo(int other);
-}
diff --git a/src/main/java/com/android/tools/r8/graph/PresortedComparable.java b/src/main/java/com/android/tools/r8/graph/PresortedComparable.java
index 075c187..e4eb4b7 100644
--- a/src/main/java/com/android/tools/r8/graph/PresortedComparable.java
+++ b/src/main/java/com/android/tools/r8/graph/PresortedComparable.java
@@ -4,41 +4,11 @@
 package com.android.tools.r8.graph;
 
 import com.android.tools.r8.naming.NamingLens;
-import java.util.Arrays;
-import java.util.List;
-import java.util.function.Function;
 
-public interface PresortedComparable<T> extends Presorted, Comparable<T> {
+public interface PresortedComparable<T> {
 
-  static <D extends DexEncodedMember<D, R>, R extends DexMember<D, R>> boolean isSorted(
-      List<? extends DexEncodedMember<D, R>> items) {
-    return isSorted(items, DexEncodedMember::toReference);
-  }
-
-  static <S, T extends Comparable<T>> boolean isSorted(S[] items, Function<S, T> getter) {
-    return isSorted(Arrays.asList(items), getter);
-  }
-
-  static <S, T extends Comparable<T>> boolean isSorted(
-      List<? extends S> items, Function<S, T> getter) {
-    T current = null;
-    for (S item : items) {
-      T next = getter.apply(item);
-      if (current != null && current.compareTo(next) >= 0) {
-        return false;
-      }
-      current = next;
-    }
-    return true;
-  }
-
-  // Slow comparison methods that make no use of indices for comparisons. These are used
-  // for sorting operations when reading dex files.
   int slowCompareTo(T other);
   int slowCompareTo(T other, NamingLens namingLens);
-  // Layered comparison methods that make use of indices for subpart comparisons. These rely
-  // on subparts already being sorted and having indices assigned.
-  int layeredCompareTo(T other, NamingLens namingLens);
 
   static <T extends PresortedComparable<T>> int slowCompare(T a, T b) {
     return a.slowCompareTo(b);
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 1ca54ba..4ec2517 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -506,6 +506,7 @@
     previous.markObsolete();
   }
 
+  // TODO(b/150736225): Don't disable this assert.
   private boolean dontAssertDefinitionFor = true;
 
   public static AppInfoWithLivenessModifier modifier() {
@@ -513,16 +514,6 @@
   }
 
   @Override
-  public void enableDefinitionForAssert() {
-    dontAssertDefinitionFor = false;
-  }
-
-  @Override
-  public void disableDefinitionForAssert() {
-    dontAssertDefinitionFor = true;
-  }
-
-  @Override
   public DexClass definitionFor(DexType type) {
     DexClass definition = super.definitionFor(type);
     assert dontAssertDefinitionFor
diff --git a/src/main/java/com/android/tools/r8/utils/OrderedMergingIterator.java b/src/main/java/com/android/tools/r8/utils/OrderedMergingIterator.java
deleted file mode 100644
index 2458a64..0000000
--- a/src/main/java/com/android/tools/r8/utils/OrderedMergingIterator.java
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.utils;
-
-import com.android.tools.r8.errors.InternalCompilerError;
-import com.android.tools.r8.graph.DexEncodedMember;
-import com.android.tools.r8.graph.DexMember;
-import java.util.Iterator;
-import java.util.List;
-import java.util.NoSuchElementException;
-
-public class OrderedMergingIterator<D extends DexEncodedMember<D, R>, R extends DexMember<D, R>>
-    implements Iterator<D> {
-
-  private final List<D> one;
-  private final List<D> other;
-  private int oneIndex = 0;
-  private int otherIndex = 0;
-
-  public OrderedMergingIterator(List<D> one, List<D> other) {
-    this.one = one;
-    this.other = other;
-  }
-
-  private D getNextChecked(List<D> list, int position) {
-    if (position >= list.size()) {
-      throw new NoSuchElementException();
-    }
-    return list.get(position);
-  }
-
-  @Override
-  public boolean hasNext() {
-    return oneIndex < one.size() || otherIndex < other.size();
-  }
-
-  @Override
-  public D next() {
-    if (oneIndex >= one.size()) {
-      return getNextChecked(other, otherIndex++);
-    }
-    if (otherIndex >= other.size()) {
-      return getNextChecked(one, oneIndex++);
-    }
-    int comparison = one.get(oneIndex).toReference().compareTo(other.get(otherIndex).toReference());
-    if (comparison < 0) {
-      return one.get(oneIndex++);
-    }
-    if (comparison == 0) {
-      throw new InternalCompilerError("Source arrays are not disjoint.");
-    }
-    return other.get(otherIndex++);
-  }
-}
diff --git a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
index b93ac8d..eeedbab 100644
--- a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
+++ b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
@@ -10,6 +10,7 @@
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.InitClassLens;
 import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.Reporter;
 import java.util.Collections;
@@ -22,6 +23,8 @@
     return new ObjectToOffsetMapping(
         DexApplication.builder(new InternalOptions(new DexItemFactory(), new Reporter()), null)
             .build(),
+        NamingLens.getIdentityLens(),
+        InitClassLens.getDefault(),
         Collections.emptyList(),
         Collections.emptyList(),
         Collections.emptyList(),
@@ -29,8 +32,7 @@
         Collections.emptyList(),
         Collections.emptyList(),
         Collections.emptyList(),
-        Collections.emptyList(),
-        InitClassLens.getDefault());
+        Collections.emptyList());
   }
 
   @Test
diff --git a/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java b/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
index 666cb87..945f3c2 100644
--- a/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
+++ b/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
@@ -25,7 +25,6 @@
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.MethodAccessFlags;
 import com.android.tools.r8.graph.ParameterAnnotationsList;
-import com.android.tools.r8.naming.NamingLens;
 import com.android.tools.r8.origin.Origin;
 import com.android.tools.r8.utils.AndroidApp;
 import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -43,7 +42,6 @@
   public void branching() {
     DexItemFactory factory = new DexItemFactory();
     DexString string = factory.createString("turn into jumbo");
-    factory.sort(NamingLens.getIdentityLens());
     Instruction[] instructions = buildInstructions(string, false);
     DexCode code = jumboStringProcess(factory, string, instructions);
     Instruction[] rewrittenInstructions = code.instructions;
@@ -60,7 +58,6 @@
   public void branching2() {
     DexItemFactory factory = new DexItemFactory();
     DexString string = factory.createString("turn into jumbo");
-    factory.sort(NamingLens.getIdentityLens());
     Instruction[] instructions = buildInstructions(string, true);
     DexCode code = jumboStringProcess(factory, string, instructions);
     Instruction[] rewrittenInstructions = code.instructions;
@@ -142,7 +139,6 @@
 
     DexItemFactory factory = inspector.getFactory();
     DexString string = factory.createString("view must have a tag");
-    factory.sort(NamingLens.getIdentityLens());
     DexCode code = jumboStringProcess(factory, string, instructions);
     Instruction[] rewrittenInstructions = code.instructions;
     assertEquals(289, countJumboStrings(rewrittenInstructions));
diff --git a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
index 8d73fad..3b3473a 100644
--- a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
@@ -44,7 +44,6 @@
 
   protected DexApplication buildApplication(AndroidApp input, InternalOptions options) {
     try {
-      options.itemFactory.resetSortedIndices();
       return new ApplicationReader(input, options, Timing.empty()).read();
     } catch (IOException | ExecutionException e) {
       throw new RuntimeException(e);
diff --git a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
index 8ecb463..6aad725 100644
--- a/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
+++ b/src/test/java/com/android/tools/r8/smali/SmaliTestBase.java
@@ -62,7 +62,6 @@
 
   protected DexApplication buildApplication(AndroidApp input, InternalOptions options) {
     try {
-      options.itemFactory.resetSortedIndices();
       return new ApplicationReader(input, options, Timing.empty()).read();
     } catch (IOException | ExecutionException e) {
       throw new RuntimeException(e);