Upgrade google-smali to 3.0.7

This project was upgraded with external_updater.
Usage: tools/external_updater/updater.sh update external/google-smali
For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md

Test: TreeHugger
Change-Id: I9150aa0e64f80c0f248e5c56e796058f45bf2298
diff --git a/METADATA b/METADATA
index 2d0a8a9..d3c83fc 100644
--- a/METADATA
+++ b/METADATA
@@ -8,12 +8,12 @@
   license_type: NOTICE
   last_upgrade_date {
     year: 2024
-    month: 2
-    day: 7
+    month: 5
+    day: 13
   }
   identifier {
     type: "Git"
     value: "https://github.com/google/smali"
-    version: "3.0.4"
+    version: "3.0.7"
   }
 }
diff --git a/baksmali/Android.bp b/baksmali/Android.bp
index 6fc3f7e..347be56 100644
--- a/baksmali/Android.bp
+++ b/baksmali/Android.bp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
- // Create a new baksmali.properties file using the correct version
+// Create a new baksmali.properties file using the correct version
 genrule {
     name: "android-baksmali_version",
-    defaults : ["android-smali_version_defaults"],
+    defaults: ["android-smali_version_defaults"],
     out: ["android-baksmali.properties"],
 }
 
@@ -35,6 +35,7 @@
     manifest: "manifest.txt",
 
     static_libs: [
+        "guava",
         "smali-dexlib2",
         "android-smali-util",
         "jcommander",
@@ -43,4 +44,4 @@
     java_resources: [":android-baksmali_version"],
 
     wrapper: ":android-baksmali_script",
-}
\ No newline at end of file
+}
diff --git a/baksmali/src/test/java/com/android/tools/smali/baksmali/InstructionMethodItemTest.java b/baksmali/src/test/java/com/android/tools/smali/baksmali/InstructionMethodItemTest.java
index 492b3c7..10ffccf 100644
--- a/baksmali/src/test/java/com/android/tools/smali/baksmali/InstructionMethodItemTest.java
+++ b/baksmali/src/test/java/com/android/tools/smali/baksmali/InstructionMethodItemTest.java
@@ -151,7 +151,8 @@
         BaksmaliWriter writer = new BaksmaliWriter(stringWriter);
         methodItem.writeTo(writer);
 
-        Assert.assertEquals("#Invalid reference\n#const-string v0, blahblahblah\nnop", stringWriter.toString());
+        Assert.assertEquals("#Invalid reference" + System.lineSeparator()
+                + "#const-string v0, blahblahblah" + System.lineSeparator() + "nop", stringWriter.toString());
     }
 
     private static class TestMethod extends BaseMethodReference implements Method {
diff --git a/baksmali/src/test/java/com/android/tools/smali/baksmali/formatter/BaksmaliWriterTest.java b/baksmali/src/test/java/com/android/tools/smali/baksmali/formatter/BaksmaliWriterTest.java
index be62162..963c8e8 100644
--- a/baksmali/src/test/java/com/android/tools/smali/baksmali/formatter/BaksmaliWriterTest.java
+++ b/baksmali/src/test/java/com/android/tools/smali/baksmali/formatter/BaksmaliWriterTest.java
@@ -179,10 +179,10 @@
                 )));
 
         Assert.assertEquals(
-                ".subannotation Lannotation/`type with spaces`;\n" +
-                        "    `element with spaces 1` = Ldefining/class/`with spaces`;->`fieldName with spaces`:Lfield/`type with spaces`;\n" +
+                ".subannotation Lannotation/`type with spaces`;" + System.lineSeparator() +
+                        "    `element with spaces 1` = Ldefining/class/`with spaces`;->`fieldName with spaces`:Lfield/`type with spaces`;" + System.lineSeparator() +
                         "    `element with spaces 2` = Ldefining/class/`with spaces`;->`methodName with spaces`(" +
-                        "L`param with spaces 1`;L`param with spaces 2`;)Lreturn/type/`with spaces`;\n" +
+                        "L`param with spaces 1`;L`param with spaces 2`;)Lreturn/type/`with spaces`;" + System.lineSeparator() +
                         ".end subannotation",
                 output.toString());
     }
@@ -196,9 +196,9 @@
                 new ImmutableMethodEncodedValue(getMethodReferenceWithSpaces()))));
 
         Assert.assertEquals(
-                "{\n" +
-                        "    Ldefining/class/`with spaces`;->`fieldName with spaces`:Lfield/`type with spaces`;,\n" +
-                        "    Ldefining/class/`with spaces`;->`methodName with spaces`(L`param with spaces 1`;L`param with spaces 2`;)Lreturn/type/`with spaces`;\n" +
+                "{" + System.lineSeparator() +
+                        "    Ldefining/class/`with spaces`;->`fieldName with spaces`:Lfield/`type with spaces`;," + System.lineSeparator() +
+                        "    Ldefining/class/`with spaces`;->`methodName with spaces`(L`param with spaces 1`;L`param with spaces 2`;)Lreturn/type/`with spaces`;" + System.lineSeparator() +
                         "}",
                 output.toString());
     }
diff --git a/build.gradle b/build.gradle
index ecc1f84..148abf7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -30,7 +30,7 @@
 
 apply plugin: 'idea'
 
-version = '3.0.4'
+version = '3.0.7'
 def jcommanderVersion = ''
 
 if (!('release' in gradle.startParameter.taskNames)) {
diff --git a/dexlib2/Android.bp b/dexlib2/Android.bp
index 1e9d6e4..0c69645 100644
--- a/dexlib2/Android.bp
+++ b/dexlib2/Android.bp
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
- java_library_host {
+java_library_host {
     name: "smali-dexlib2",
 
     srcs: [
@@ -23,9 +23,7 @@
     ],
 
     static_libs: [
-        "guava",
         "jsr305",
-        "auto_android_annotation_stubs",
     ],
 
     errorprone: {
@@ -43,13 +41,8 @@
         ":third_party-smali-dexlib2",
     ],
 
-    libs: [
-        "guava",
-    ],
-
     static_libs: [
         "jsr305",
-        "auto_android_annotation_stubs",
     ],
 
     errorprone: {
@@ -59,7 +52,6 @@
     },
 }
 
-
 java_library {
     name: "smali-dexlib2-device",
 
@@ -68,19 +60,12 @@
         ":third_party-smali-dexlib2",
     ],
 
-    libs: [
-        "guava",
-    ],
-
     static_libs: [
         "jsr305",
     ],
 
     sdk_version: "system_server_current",
     min_sdk_version: "33",
-    apex_available: [
-        "com.android.adservices"
-    ],
 
     optimize: {
         enabled: true,
@@ -92,4 +77,8 @@
             "-Xep:ComparableType:WARN",
         ],
     },
-}
\ No newline at end of file
+
+    apex_available: [
+        "//apex_available:anyapex",
+    ],
+}
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/DexFileFactory.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/DexFileFactory.java
index c464c47..eb5675a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/DexFileFactory.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/DexFileFactory.java
@@ -55,6 +55,7 @@
 import java.io.FileNotFoundException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Collections;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
@@ -460,7 +461,7 @@
         }
 
         @Nonnull @Override public List<String> getDexEntryNames() {
-            return unmodifiableList(List.of(entryName));
+            return Collections.singletonList(entryName);
         }
 
         @Nullable @Override public DexEntry<DexBackedDexFile> getEntry(@Nonnull String entryName) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/MethodHandleType.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/MethodHandleType.java
index 6ba1726..c0003de 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/MethodHandleType.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/MethodHandleType.java
@@ -50,16 +50,21 @@
     public static final int INVOKE_DIRECT = 7;
     public static final int INVOKE_INTERFACE = 8;
 
-    private static final Map<Integer, String> methodHandleTypeNames = unmodifiableMap(Map.of(
-            STATIC_PUT, "static-put",
-            STATIC_GET, "static-get",
-            INSTANCE_PUT, "instance-put",
-            INSTANCE_GET, "instance-get",
-            INVOKE_STATIC, "invoke-static",
-            INVOKE_INSTANCE, "invoke-instance",
-            INVOKE_CONSTRUCTOR, "invoke-constructor",
-            INVOKE_DIRECT, "invoke-direct",
-            INVOKE_INTERFACE, "invoke-interface"));
+    private static final Map<Integer, String> methodHandleTypeNames;
+
+    static {
+        Map<Integer, String> temp = new HashMap<>();
+        temp.put(STATIC_PUT, "static-put");
+        temp.put(STATIC_GET, "static-get");
+        temp.put(INSTANCE_PUT, "instance-put");
+        temp.put(INSTANCE_GET, "instance-get");
+        temp.put(INVOKE_STATIC, "invoke-static");
+        temp.put(INVOKE_INSTANCE, "invoke-instance");
+        temp.put(INVOKE_CONSTRUCTOR, "invoke-constructor");
+        temp.put(INVOKE_DIRECT, "invoke-direct");
+        temp.put(INVOKE_INTERFACE, "invoke-interface");
+        methodHandleTypeNames = unmodifiableMap(temp);
+    }
 
     private static final Map<String, Integer> inverse = getInverse();
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcode.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcode.java
index d0ca08d..bd8dc5f 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcode.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcode.java
@@ -30,12 +30,12 @@
 
 package com.android.tools.smali.dexlib2;
 
-import com.google.common.collect.ImmutableRangeMap;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Range;
-import com.google.common.collect.RangeMap;
+import com.android.tools.smali.util.UnmodifiableRangeMap;
+import com.android.tools.smali.util.Range;
 
 import javax.annotation.Nonnull;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.List;
 
 public enum Opcode
@@ -348,8 +348,8 @@
 
     // values and minApis provide a mapping of api -> bytecode value.
     // the apis in minApis are guaranteed to be
-    public final RangeMap<Integer, Short> apiToValueMap;
-    public final RangeMap<Integer, Short> artVersionToValueMap;
+    public final UnmodifiableRangeMap<Integer, Short> apiToValueMap;
+    public final UnmodifiableRangeMap<Integer, Short> artVersionToValueMap;
 
     public final String name;
     public final int referenceType;
@@ -371,8 +371,8 @@
 
     Opcode(List<VersionConstraint> versionConstraints, String opcodeName, int referenceType, int referenceType2,
            Format format, int flags) {
-        ImmutableRangeMap.Builder<Integer, Short> apiToValueBuilder = ImmutableRangeMap.builder();
-        ImmutableRangeMap.Builder<Integer, Short> artVersionToValueBuilder = ImmutableRangeMap.builder();
+        UnmodifiableRangeMap.Builder<Integer, Short> apiToValueBuilder = UnmodifiableRangeMap.builder();
+        UnmodifiableRangeMap.Builder<Integer, Short> artVersionToValueBuilder = UnmodifiableRangeMap.builder();
 
         for (VersionConstraint versionConstraint : versionConstraints) {
             if (!versionConstraint.apiRange.isEmpty()) {
@@ -393,41 +393,41 @@
     }
 
     private static List<VersionConstraint> firstApi(int opcodeValue, int api) {
-        return Lists.newArrayList(new VersionConstraint(Range.atLeast(api), Range.openClosed(0, 0), opcodeValue));
+        return Arrays.asList(new VersionConstraint(Range.atLeast(api), Range.openClosed(0, 0), opcodeValue));
     }
 
     private static List<VersionConstraint> lastApi(int opcodeValue, int api) {
-        return Lists.newArrayList(new VersionConstraint(Range.atMost(api), Range.openClosed(0, 0), opcodeValue));
+        return Arrays.asList(new VersionConstraint(Range.atMost(api), Range.openClosed(0, 0), opcodeValue));
     }
 
     private static List<VersionConstraint> betweenApi(int opcodeValue, int minApi, int maxApi) {
-        return Lists.newArrayList(new VersionConstraint(Range.closed(minApi, maxApi), Range.openClosed(0, 0),
+        return Arrays.asList(new VersionConstraint(Range.closed(minApi, maxApi), Range.openClosed(0, 0),
                 opcodeValue));
     }
 
     private static List<VersionConstraint> firstArtVersion(int opcodeValue, int artVersion) {
-        return Lists.newArrayList(new VersionConstraint(Range.openClosed(0, 0), Range.atLeast(artVersion), opcodeValue));
+        return Arrays.asList(new VersionConstraint(Range.openClosed(0, 0), Range.atLeast(artVersion), opcodeValue));
     }
 
     private static List<VersionConstraint> lastArtVersion(int opcodeValue, int artVersion) {
-        return Lists.newArrayList(new VersionConstraint(Range.openClosed(0, 0), Range.atMost(artVersion), opcodeValue));
+        return Arrays.asList(new VersionConstraint(Range.openClosed(0, 0), Range.atMost(artVersion), opcodeValue));
     }
 
     private static List<VersionConstraint> allVersions(int opcodeValue) {
-        return Lists.newArrayList(new VersionConstraint(Range.<Integer>all(), Range.<Integer>all(), opcodeValue));
+        return Arrays.asList(new VersionConstraint(Range.allValues(), Range.allValues(), opcodeValue));
     }
 
     private static List<VersionConstraint> allApis(int opcodeValue) {
-        return Lists.newArrayList(new VersionConstraint(Range.<Integer>all(), Range.openClosed(0, 0), opcodeValue));
+        return Arrays.asList(new VersionConstraint(Range.allValues(), Range.openClosed(0, 0), opcodeValue));
     }
 
     private static List<VersionConstraint> allArtVersions(int opcodeValue) {
-        return Lists.newArrayList(new VersionConstraint(Range.openClosed(0, 0), Range.<Integer>all(), opcodeValue));
+        return Arrays.asList(new VersionConstraint(Range.openClosed(0, 0), Range.allValues(), opcodeValue));
     }
 
     @SuppressWarnings("unchecked")
     private static List<VersionConstraint> combine(List<VersionConstraint>... versionConstraints) {
-        List<VersionConstraint> combinedList = Lists.newArrayList();
+        List<VersionConstraint> combinedList = new ArrayList<>();
         for (List<VersionConstraint> versionConstraintList: versionConstraints) {
             combinedList.addAll(versionConstraintList);
         }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcodes.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcodes.java
index 176c517..4c5b597 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcodes.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/Opcodes.java
@@ -30,16 +30,16 @@
 
 package com.android.tools.smali.dexlib2;
 
-import com.google.common.collect.RangeMap;
+import static com.android.tools.smali.dexlib2.VersionMap.NO_VERSION;
+import static com.android.tools.smali.dexlib2.VersionMap.mapApiToArtVersion;
+import static com.android.tools.smali.dexlib2.VersionMap.mapArtVersionToApi;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.EnumMap;
 import java.util.HashMap;
 
-import static com.android.tools.smali.dexlib2.VersionMap.NO_VERSION;
-import static com.android.tools.smali.dexlib2.VersionMap.mapApiToArtVersion;
-import static com.android.tools.smali.dexlib2.VersionMap.mapArtVersionToApi;
+import com.android.tools.smali.util.UnmodifiableRangeMap;
 
 public class Opcodes {
 
@@ -103,7 +103,7 @@
         }
 
         for (Opcode opcode: Opcode.values()) {
-            RangeMap<Integer, Short> versionToValueMap;
+            UnmodifiableRangeMap<Integer, Short> versionToValueMap;
 
             if (isArt()) {
                 versionToValueMap = opcode.artVersionToValueMap;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/AnalyzedInstruction.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/AnalyzedInstruction.java
index b67fee7..adc1848 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/AnalyzedInstruction.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/AnalyzedInstruction.java
@@ -42,15 +42,15 @@
 import com.android.tools.smali.dexlib2.iface.reference.Reference;
 import com.android.tools.smali.dexlib2.iface.reference.TypeReference;
 import com.android.tools.smali.util.ExceptionWithContext;
-import com.google.common.base.Objects;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
 
+import java.util.ArrayList;
 import java.util.BitSet;
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.SortedSet;
 import java.util.TreeSet;
 import javax.annotation.Nonnull;
@@ -301,7 +301,7 @@
     protected boolean overridePredecessorRegisterType(@Nonnull AnalyzedInstruction predecessor, int registerNumber,
                                                       @Nonnull RegisterType registerType, BitSet verifiedInstructions) {
         if (predecessorRegisterOverrides == null) {
-            predecessorRegisterOverrides = Maps.newHashMap();
+            predecessorRegisterOverrides = new HashMap<>();
         }
         predecessorRegisterOverrides.put(new PredecessorOverrideKey(predecessor, registerNumber), registerType);
 
@@ -482,7 +482,7 @@
     }
 
     public List<Integer> getSetRegisters() {
-        List<Integer> setRegisters = Lists.newArrayList();
+        List<Integer> setRegisters = new ArrayList<>();
 
         if (instruction.getOpcode().setsRegister()) {
             setRegisters.add(getDestinationRegister());
@@ -667,12 +667,12 @@
             if (this == o) return true;
             if (o == null || getClass() != o.getClass()) return false;
             PredecessorOverrideKey that = (PredecessorOverrideKey)o;
-            return com.google.common.base.Objects.equal(registerNumber, that.registerNumber) &&
-                    Objects.equal(analyzedInstruction, that.analyzedInstruction);
+            return Objects.equals(registerNumber, that.registerNumber) &&
+                    Objects.equals(analyzedInstruction, that.analyzedInstruction);
         }
 
         @Override public int hashCode() {
-            return Objects.hashCode(analyzedInstruction, registerNumber);
+            return Objects.hash(analyzedInstruction, registerNumber);
         }
     }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ArrayProto.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ArrayProto.java
index 740dbc8..699b423 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ArrayProto.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ArrayProto.java
@@ -36,7 +36,7 @@
 import com.android.tools.smali.dexlib2.immutable.reference.ImmutableFieldReference;
 import com.android.tools.smali.dexlib2.util.TypeUtils;
 import com.android.tools.smali.util.ExceptionWithContext;
-import com.google.common.base.Strings;
+import com.android.tools.smali.util.StringUtils;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -141,7 +141,7 @@
         return other.getCommonSuperclass(this);
     }
 
-    private static final String BRACKETS = Strings.repeat("[", 256);
+    private static final String BRACKETS = StringUtils.repeat("[", 256);
 
     @Nonnull
     private static String makeArrayType(@Nonnull String elementType, int dimensions) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ClassPath.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ClassPath.java
index 1b6f0a0..e2aadc6 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ClassPath.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ClassPath.java
@@ -32,21 +32,20 @@
 
 import com.android.tools.smali.dexlib2.Opcodes;
 import com.android.tools.smali.dexlib2.analysis.reflection.ReflectionClassDef;
+import com.android.tools.smali.dexlib2.analysis.util.LruCache;
+import com.android.tools.smali.dexlib2.analysis.util.MemoizingSupplier;
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.immutable.ImmutableDexFile;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.cache.CacheBuilder;
-import com.google.common.cache.CacheLoader;
-import com.google.common.cache.LoadingCache;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Lists;
+import com.android.tools.smali.util.IteratorUtils;
 
 import javax.annotation.Nonnull;
 import java.io.IOException;
 import java.io.Serializable;
 import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.List;
+import java.util.function.Supplier;
 
 public class ClassPath {
     @Nonnull private final TypeProto unknownClass;
@@ -104,7 +103,7 @@
         loadPrimitiveType("D");
         loadPrimitiveType("L");
 
-        this.classProviders = Lists.newArrayList(classProviders);
+        this.classProviders = (List<ClassProvider>)IteratorUtils.toList(classProviders);
         this.classProviders.add(getBasicClasses());
     }
 
@@ -114,13 +113,14 @@
 
     private static ClassProvider getBasicClasses() {
         // fallbacks for some special classes that we assume are present
-        return new DexClassProvider(new ImmutableDexFile(Opcodes.getDefault(), ImmutableSet.of(
+        return new DexClassProvider(new ImmutableDexFile(Opcodes.getDefault(),
+            Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
                 new ReflectionClassDef(Class.class),
                 new ReflectionClassDef(Cloneable.class),
                 new ReflectionClassDef(Object.class),
                 new ReflectionClassDef(Serializable.class),
                 new ReflectionClassDef(String.class),
-                new ReflectionClassDef(Throwable.class))));
+                new ReflectionClassDef(Throwable.class))))));
     }
 
     public boolean isArt() {
@@ -129,21 +129,19 @@
 
     @Nonnull
     public TypeProto getClass(@Nonnull CharSequence type) {
-        return loadedClasses.getUnchecked(type.toString());
+        return loadedClasses.get(type.toString());
     }
 
-    private final CacheLoader<String, TypeProto> classLoader = new CacheLoader<String, TypeProto>() {
-        @Override public TypeProto load(String type) throws Exception {
-            if (type.charAt(0) == '[') {
-                return new ArrayProto(ClassPath.this, type);
+    @Nonnull private LruCache<String, TypeProto> loadedClasses = new LruCache<String, TypeProto>(30000) {
+        @Override protected TypeProto create(String key) {
+            if (key.charAt(0) == '[') {
+                return new ArrayProto(ClassPath.this, key);
             } else {
-                return new ClassProto(ClassPath.this, type);
+                return new ClassProto(ClassPath.this, key);
             }
         }
     };
 
-    @Nonnull private LoadingCache<String, TypeProto> loadedClasses = CacheBuilder.newBuilder().build(classLoader);
-
     @Nonnull
     public ClassDef getClassDef(String type) {
         for (ClassProvider provider: classProviders) {
@@ -164,7 +162,7 @@
         return checkPackagePrivateAccess;
     }
 
-    private final Supplier<OdexedFieldInstructionMapper> fieldInstructionMapperSupplier = Suppliers.memoize(
+    private final Supplier<OdexedFieldInstructionMapper> fieldInstructionMapperSupplier = MemoizingSupplier.memoize(
             new Supplier<OdexedFieldInstructionMapper>() {
                 @Override public OdexedFieldInstructionMapper get() {
                     return new OdexedFieldInstructionMapper(isArt());
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ClassPathResolver.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ClassPathResolver.java
index e5d92da..6057b14 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ClassPathResolver.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ClassPathResolver.java
@@ -36,14 +36,13 @@
 import com.android.tools.smali.dexlib2.iface.DexFile;
 import com.android.tools.smali.dexlib2.iface.MultiDexContainer;
 import com.android.tools.smali.dexlib2.iface.MultiDexContainer.DexEntry;
-import com.google.common.base.Joiner;
-import com.google.common.base.Splitter;
-import com.google.common.collect.Lists;
+import com.android.tools.smali.util.StringUtils;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.io.File;
 import java.io.IOException;
+import java.util.Arrays;
 import java.util.List;
 
 public class ClassPathResolver {
@@ -182,7 +181,6 @@
         // It's not a local path, so let's try to resolve it as a device path, relative to one of the provided
         // directories
         List<String> pathComponents = splitDevicePath(entry);
-        Joiner pathJoiner = Joiner.on(File.separatorChar);
 
         for (String directory: classPathDirs) {
             File directoryFile = new File(directory);
@@ -191,7 +189,8 @@
             }
 
             for (int i=0; i<pathComponents.size(); i++) {
-                String partialPath = pathJoiner.join(pathComponents.subList(i, pathComponents.size()));
+                String partialPath = StringUtils.join(
+                        pathComponents.subList(i, pathComponents.size()), File.separator);
                 File entryFile = new File(directoryFile, partialPath);
                 if (entryFile.exists() && entryFile.isFile()) {
                     pathEntryLoader.loadEntry(entryFile, true);
@@ -205,7 +204,7 @@
 
     @Nonnull
     private static List<String> splitDevicePath(@Nonnull String path) {
-        return Lists.newArrayList(Splitter.on('/').split(path));
+        return Arrays.asList(path.split("/"));
     }
 
     static class NotFoundException extends Exception {
@@ -250,14 +249,14 @@
         }
 
         if (apiLevel <= 8) {
-            return Lists.newArrayList(
+            return Arrays.asList(
                     "/system/framework/core.jar",
                     "/system/framework/ext.jar",
                     "/system/framework/framework.jar",
                     "/system/framework/android.policy.jar",
                     "/system/framework/services.jar");
         } else if (apiLevel <= 11) {
-            return Lists.newArrayList(
+            return Arrays.asList(
                     "/system/framework/core.jar",
                     "/system/framework/bouncycastle.jar",
                     "/system/framework/ext.jar",
@@ -266,7 +265,7 @@
                     "/system/framework/services.jar",
                     "/system/framework/core-junit.jar");
         } else if (apiLevel <= 13) {
-            return Lists.newArrayList(
+            return Arrays.asList(
                     "/system/framework/core.jar",
                     "/system/framework/apache-xml.jar",
                     "/system/framework/bouncycastle.jar",
@@ -276,7 +275,7 @@
                     "/system/framework/services.jar",
                     "/system/framework/core-junit.jar");
         } else if (apiLevel <= 15) {
-            return Lists.newArrayList(
+            return Arrays.asList(
                     "/system/framework/core.jar",
                     "/system/framework/core-junit.jar",
                     "/system/framework/bouncycastle.jar",
@@ -288,7 +287,7 @@
                     "/system/framework/filterfw.jar");
         } else if (apiLevel <= 17) {
             // this is correct as of api 17/4.2.2
-            return Lists.newArrayList(
+            return Arrays.asList(
                     "/system/framework/core.jar",
                     "/system/framework/core-junit.jar",
                     "/system/framework/bouncycastle.jar",
@@ -300,7 +299,7 @@
                     "/system/framework/services.jar",
                     "/system/framework/apache-xml.jar");
         } else if (apiLevel <= 18) {
-            return Lists.newArrayList(
+            return Arrays.asList(
                     "/system/framework/core.jar",
                     "/system/framework/core-junit.jar",
                     "/system/framework/bouncycastle.jar",
@@ -313,7 +312,7 @@
                     "/system/framework/services.jar",
                     "/system/framework/apache-xml.jar");
         } else if (apiLevel <= 19) {
-            return Lists.newArrayList(
+            return Arrays.asList(
                     "/system/framework/core.jar",
                     "/system/framework/conscrypt.jar",
                     "/system/framework/core-junit.jar",
@@ -329,7 +328,7 @@
                     "/system/framework/apache-xml.jar",
                     "/system/framework/webviewchromium.jar");
         } else if (apiLevel <= 22) {
-            return Lists.newArrayList(
+            return Arrays.asList(
                     "/system/framework/core-libart.jar",
                     "/system/framework/conscrypt.jar",
                     "/system/framework/okhttp.jar",
@@ -344,7 +343,7 @@
                     "/system/framework/android.policy.jar",
                     "/system/framework/apache-xml.jar");
         } else if (apiLevel <= 23) {
-            return Lists.newArrayList(
+            return Arrays.asList(
                     "/system/framework/core-libart.jar",
                     "/system/framework/conscrypt.jar",
                     "/system/framework/okhttp.jar",
@@ -358,7 +357,7 @@
                     "/system/framework/apache-xml.jar",
                     "/system/framework/org.apache.http.legacy.boot.jar");
         } else /*if (apiLevel <= 24)*/ {
-            return Lists.newArrayList(
+            return Arrays.asList(
                     "/system/framework/core-oj.jar",
                     "/system/framework/core-libart.jar",
                     "/system/framework/conscrypt.jar",
@@ -378,7 +377,7 @@
     private static List<String> bootClassPathForOat(@Nonnull OatFile oatFile) {
         List<String> bcp = oatFile.getBootClassPath();
         if(bcp.isEmpty()) {
-            return Lists.newArrayList("boot.oat");
+            return Arrays.asList("boot.oat");
         } else {
             return replaceElementsSuffix(bcp, ".art", ".oat");
         }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ClassProto.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ClassProto.java
index 34743ec..368eda9 100755
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ClassProto.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/ClassProto.java
@@ -32,6 +32,7 @@
 
 import com.android.tools.smali.dexlib2.AccessFlags;
 import com.android.tools.smali.dexlib2.HiddenApiRestriction;
+import com.android.tools.smali.dexlib2.analysis.util.MemoizingSupplier;
 import com.android.tools.smali.dexlib2.analysis.util.TypeProtoUtils;
 import com.android.tools.smali.dexlib2.base.reference.BaseMethodReference;
 import com.android.tools.smali.dexlib2.iface.Annotation;
@@ -45,17 +46,9 @@
 import com.android.tools.smali.dexlib2.util.AlignmentUtils;
 import com.android.tools.smali.dexlib2.util.MethodUtil;
 import com.android.tools.smali.util.ExceptionWithContext;
+import com.android.tools.smali.util.IteratorUtils;
 import com.android.tools.smali.util.SparseArray;
-import com.google.common.base.Joiner;
-import com.google.common.base.Predicates;
-import com.google.common.base.Supplier;
-import com.google.common.base.Suppliers;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.primitives.Ints;
+import com.android.tools.smali.util.StringUtils;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -66,9 +59,11 @@
 import java.util.List;
 import java.util.PriorityQueue;
 import java.util.Set;
+import java.util.function.Supplier;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Map.Entry;
+import java.util.function.Predicate;
 
 /**
  * A class "prototype". This contains things like the interfaces, the superclass, the vtable and the instance fields
@@ -105,7 +100,7 @@
     }
 
 
-    @Nonnull private final Supplier<ClassDef> classDefSupplier = Suppliers.memoize(new Supplier<ClassDef>() {
+    @Nonnull private final Supplier<ClassDef> classDefSupplier = MemoizingSupplier.memoize(new Supplier<ClassDef>() {
         @Override public ClassDef get() {
             return classPath.getClassDef(type);
         }
@@ -151,10 +146,10 @@
      */
     @Nonnull
     private final Supplier<LinkedHashMap<String, ClassDef>> preDefaultMethodInterfaceSupplier =
-            Suppliers.memoize(new Supplier<LinkedHashMap<String, ClassDef>>() {
+            MemoizingSupplier.memoize(new Supplier<LinkedHashMap<String, ClassDef>>() {
                 @Override public LinkedHashMap<String, ClassDef> get() {
                     Set<String> unresolvedInterfaces = new HashSet<>(0);
-                    LinkedHashMap<String, ClassDef> interfaces = Maps.newLinkedHashMap();
+                    LinkedHashMap<String, ClassDef> interfaces = new LinkedHashMap<>();
 
                     try {
                         for (String interfaceType: getClassDef().getInterfaces()) {
@@ -227,10 +222,10 @@
      */
     @Nonnull
     private final Supplier<LinkedHashMap<String, ClassDef>> postDefaultMethodInterfaceSupplier =
-            Suppliers.memoize(new Supplier<LinkedHashMap<String, ClassDef>>() {
+            MemoizingSupplier.memoize(new Supplier<LinkedHashMap<String, ClassDef>>() {
                 @Override public LinkedHashMap<String, ClassDef> get() {
                     Set<String> unresolvedInterfaces = new HashSet<String>(0);
-                    LinkedHashMap<String, ClassDef> interfaces = Maps.newLinkedHashMap();
+                    LinkedHashMap<String, ClassDef> interfaces = new LinkedHashMap<>();
 
                     String superclass = getSuperclass();
                     if (superclass != null) {
@@ -290,7 +285,7 @@
     @Nonnull
     protected Set<String> getUnresolvedInterfaces() {
         if (unresolvedInterfaces == null) {
-            return ImmutableSet.of();
+            return Collections.emptySet();
         }
         return unresolvedInterfaces;
     }
@@ -305,12 +300,15 @@
      */
     @Nonnull
     protected Iterable<ClassDef> getDirectInterfaces() {
-        Iterable<ClassDef> directInterfaces =
-                FluentIterable.from(getInterfaces().values()).filter(Predicates.notNull());
+        Iterable<ClassDef> directInterfaces = IteratorUtils.filter(getInterfaces().values(), new Predicate<ClassDef>() {
+            @Override public boolean test(@Nullable ClassDef input) {
+                return input != null;
+            }
+        });
 
         if (!interfacesFullyResolved) {
             throw new UnresolvedClassException("Interfaces for class %s not fully resolved: %s", getType(),
-                    Joiner.on(',').join(getUnresolvedInterfaces()));
+                    StringUtils.join(getUnresolvedInterfaces(), ","));
         }
 
         return directInterfaces;
@@ -428,15 +426,17 @@
             return classPath.getUnknownClass();
         }
 
-        List<TypeProto> thisChain = Lists.<TypeProto>newArrayList(this);
-        Iterables.addAll(thisChain, TypeProtoUtils.getSuperclassChain(this));
+        List<TypeProto> thisChain = new ArrayList<>();
+        thisChain.add(this);
+        IteratorUtils.addAll(thisChain, TypeProtoUtils.getSuperclassChain(this).iterator());
 
-        List<TypeProto> otherChain = Lists.newArrayList(other);
-        Iterables.addAll(otherChain, TypeProtoUtils.getSuperclassChain(other));
+        List<TypeProto> otherChain = new ArrayList<>();
+        otherChain.add(other);
+        IteratorUtils.addAll(otherChain, TypeProtoUtils.getSuperclassChain(other).iterator());
 
         // reverse them, so that the first entry is either Ljava/lang/Object; or Ujava/lang/Object;
-        thisChain = Lists.reverse(thisChain);
-        otherChain = Lists.reverse(otherChain);
+        Collections.reverse(thisChain);
+        Collections.reverse(otherChain);
 
         for (int i=Math.min(thisChain.size(), otherChain.size())-1; i>=0; i--) {
             TypeProto typeProto = thisChain.get(i);
@@ -507,7 +507,7 @@
     }
 
     @Nonnull private final Supplier<SparseArray<FieldReference>> dalvikInstanceFieldsSupplier =
-            Suppliers.memoize(new Supplier<SparseArray<FieldReference>>() {
+            MemoizingSupplier.memoize(new Supplier<SparseArray<FieldReference>>() {
                 @Override public SparseArray<FieldReference> get() {
                     //This is a bit of an "involved" operation. We need to follow the same algorithm that dalvik uses to
                     //arrange fields, so that we end up with the same field offsets (which is needed for deodexing).
@@ -654,7 +654,7 @@
 
                 @Nonnull
                 private ArrayList<Field> getSortedInstanceFields(@Nonnull ClassDef classDef) {
-                    ArrayList<Field> fields = Lists.newArrayList(classDef.getInstanceFields());
+                    ArrayList<Field> fields = (ArrayList<Field>)IteratorUtils.toList(classDef.getInstanceFields());
                     Collections.sort(fields);
                     return fields;
                 }
@@ -677,21 +677,21 @@
             if (oatVersion >= 67) {
                 return new FieldGap(offset, size) {
                     @Override public int compareTo(@Nonnull FieldGap o) {
-                        int result = Ints.compare(o.size, size);
+                        int result = Integer.compare(o.size, size);
                         if (result != 0) {
                             return result;
                         }
-                        return Ints.compare(offset, o.offset);
+                        return Integer.compare(offset, o.offset);
                     }
                 };
             } else {
                 return new FieldGap(offset, size) {
                     @Override public int compareTo(@Nonnull FieldGap o) {
-                        int result = Ints.compare(size, o.size);
+                        int result = Integer.compare(size, o.size);
                         if (result != 0) {
                             return result;
                         }
-                        return Ints.compare(o.offset, offset);
+                        return Integer.compare(o.offset, offset);
                     }
                 };
             }
@@ -704,7 +704,7 @@
     }
 
     @Nonnull private final Supplier<SparseArray<FieldReference>> artInstanceFieldsSupplier =
-            Suppliers.memoize(new Supplier<SparseArray<FieldReference>>() {
+            MemoizingSupplier.memoize(new Supplier<SparseArray<FieldReference>>() {
 
                 @Override public SparseArray<FieldReference> get() {
                     // We need to follow the same algorithm that art uses to arrange fields, so that we end up with the
@@ -781,10 +781,10 @@
 
                 @Nonnull
                 private ArrayList<Field> getSortedInstanceFields(@Nonnull ClassDef classDef) {
-                    ArrayList<Field> fields = Lists.newArrayList(classDef.getInstanceFields());
+                    ArrayList<Field> fields = (ArrayList<Field>)IteratorUtils.toList(classDef.getInstanceFields());
                     Collections.sort(fields, new Comparator<Field>() {
                         @Override public int compare(Field field1, Field field2) {
-                            int result = Ints.compare(getFieldSortOrder(field1), getFieldSortOrder(field2));
+                            int result = Integer.compare(getFieldSortOrder(field1), getFieldSortOrder(field2));
                             if (result != 0) {
                                 return result;
                             }
@@ -891,9 +891,9 @@
     }
 
     //TODO: check the case when we have a package private method that overrides an interface method
-    @Nonnull private final Supplier<List<Method>> preDefaultMethodVtableSupplier = Suppliers.memoize(new Supplier<List<Method>>() {
+    @Nonnull private final Supplier<List<Method>> preDefaultMethodVtableSupplier = MemoizingSupplier.memoize(new Supplier<List<Method>>() {
         @Override public List<Method> get() {
-            List<Method> vtable = Lists.newArrayList();
+            List<Method> vtable = new ArrayList<>();
 
             //copy the virtual methods from the superclass
             String superclassType;
@@ -926,7 +926,7 @@
                 // we don't end up trying to call invoke-virtual using an interface, which will fail verification
                 Iterable<ClassDef> interfaces = getDirectInterfaces();
                 for (ClassDef interfaceDef: interfaces) {
-                    List<Method> interfaceMethods = Lists.newArrayList();
+                    List<Method> interfaceMethods = new ArrayList<>();
                     for (Method interfaceMethod: interfaceDef.getVirtualMethods()) {
                         interfaceMethods.add(new ReparentedMethod(interfaceMethod, type));
                     }
@@ -942,9 +942,9 @@
      * produce multiple vtable entries for a given virtual method. This supplier duplicates this buggy logic in order to
      * generate an identical vtable
      */
-    @Nonnull private final Supplier<List<Method>> buggyPostDefaultMethodVtableSupplier = Suppliers.memoize(new Supplier<List<Method>>() {
+    @Nonnull private final Supplier<List<Method>> buggyPostDefaultMethodVtableSupplier = MemoizingSupplier.memoize(new Supplier<List<Method>>() {
         @Override public List<Method> get() {
-            List<Method> vtable = Lists.newArrayList();
+            List<Method> vtable = new ArrayList<>();
 
             //copy the virtual methods from the superclass
             String superclassType;
@@ -973,13 +973,13 @@
             if (!isInterface()) {
                 addToVtable(getClassDef().getVirtualMethods(), vtable, true, true);
 
-                List<String> interfaces = Lists.newArrayList(getInterfaces().keySet());
+                List<String> interfaces = new ArrayList<>(getInterfaces().keySet());
 
-                List<Method> defaultMethods = Lists.newArrayList();
-                List<Method> defaultConflictMethods = Lists.newArrayList();
-                List<Method> mirandaMethods = Lists.newArrayList();
+                List<Method> defaultMethods = new ArrayList<>();
+                List<Method> defaultConflictMethods = new ArrayList<>();
+                List<Method> mirandaMethods = new ArrayList<>();
 
-                final HashMap<MethodReference, Integer> methodOrder = Maps.newHashMap();
+                final HashMap<MethodReference, Integer> methodOrder = new HashMap<>();
 
                 for (int i=interfaces.size()-1; i>=0; i--) {
                     String interfaceType = interfaces.get(i);
@@ -1070,7 +1070,7 @@
 
                 Comparator<MethodReference> comparator = new Comparator<MethodReference>() {
                     @Override public int compare(MethodReference o1, MethodReference o2) {
-                        return Ints.compare(methodOrder.get(o1), methodOrder.get(o2));
+                        return Integer.compare(methodOrder.get(o1), methodOrder.get(o2));
                     }
                 };
 
@@ -1089,9 +1089,9 @@
         }
     });
 
-    @Nonnull private final Supplier<List<Method>> postDefaultMethodVtableSupplier = Suppliers.memoize(new Supplier<List<Method>>() {
+    @Nonnull private final Supplier<List<Method>> postDefaultMethodVtableSupplier = MemoizingSupplier.memoize(new Supplier<List<Method>>() {
         @Override public List<Method> get() {
-            List<Method> vtable = Lists.newArrayList();
+            List<Method> vtable = new ArrayList<>();
 
             //copy the virtual methods from the superclass
             String superclassType;
@@ -1120,13 +1120,14 @@
             if (!isInterface()) {
                 addToVtable(getClassDef().getVirtualMethods(), vtable, true, true);
 
-                Iterable<ClassDef> interfaces = Lists.reverse(Lists.newArrayList(getDirectInterfaces()));
+                List<ClassDef> interfaces = IteratorUtils.toList(getDirectInterfaces());
+                Collections.reverse(interfaces);
 
-                List<Method> defaultMethods = Lists.newArrayList();
-                List<Method> defaultConflictMethods = Lists.newArrayList();
-                List<Method> mirandaMethods = Lists.newArrayList();
+                List<Method> defaultMethods = new ArrayList<>();
+                List<Method> defaultConflictMethods = new ArrayList<>();
+                List<Method> mirandaMethods = new ArrayList<>();
 
-                final HashMap<MethodReference, Integer> methodOrder = Maps.newHashMap();
+                final HashMap<MethodReference, Integer> methodOrder = new HashMap<>();
 
                 for (ClassDef interfaceDef: interfaces) {
                     for (Method interfaceMethod : interfaceDef.getVirtualMethods()) {
@@ -1190,7 +1191,7 @@
 
                 Comparator<MethodReference> comparator = new Comparator<MethodReference>() {
                     @Override public int compare(MethodReference o1, MethodReference o2) {
-                        return Ints.compare(methodOrder.get(o1), methodOrder.get(o2));
+                        return Integer.compare(methodOrder.get(o1), methodOrder.get(o2));
                     }
                 };
 
@@ -1211,7 +1212,7 @@
     private void addToVtable(@Nonnull Iterable<? extends Method> localMethods, @Nonnull List<Method> vtable,
                              boolean replaceExisting, boolean sort) {
         if (sort) {
-            ArrayList<Method> methods = Lists.newArrayList(localMethods);
+            ArrayList<Method> methods = (ArrayList<Method>)IteratorUtils.toList(localMethods);
             Collections.sort(methods);
             localMethods = methods;
         }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/CustomInlineMethodResolver.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/CustomInlineMethodResolver.java
index 7c59c4b..a78b092 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/CustomInlineMethodResolver.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/CustomInlineMethodResolver.java
@@ -37,14 +37,14 @@
 import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter;
 import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodReference;
 import com.android.tools.smali.dexlib2.immutable.util.ParamUtil;
-import com.google.common.io.Files;
+import com.android.tools.smali.util.InputStreamUtil;
 
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.IOException;
+import java.io.FileInputStream;
 import java.io.StringReader;
 import javax.annotation.Nonnull;
-import java.nio.charset.Charset;
 import java.nio.charset.StandardCharsets;
 import java.util.ArrayList;
 import java.util.List;
@@ -85,7 +85,8 @@
     }
 
     public CustomInlineMethodResolver(@Nonnull ClassPath classPath, @Nonnull File inlineTable) throws IOException {
-        this(classPath, Files.asCharSource(inlineTable, StandardCharsets.UTF_8).read());
+        this(classPath, new String(
+            InputStreamUtil.toByteArray(new FileInputStream(inlineTable)), StandardCharsets.UTF_8));
     }
 
     @Override
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/DexClassProvider.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/DexClassProvider.java
index db9fb99..f0eb027 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/DexClassProvider.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/DexClassProvider.java
@@ -32,14 +32,14 @@
 
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.iface.DexFile;
-import com.google.common.collect.Maps;
 
 import javax.annotation.Nullable;
+import java.util.HashMap;
 import java.util.Map;
 
 public class DexClassProvider implements ClassProvider {
     private final DexFile dexFile;
-    private Map<String, ClassDef> classMap = Maps.newHashMap();
+    private Map<String, ClassDef> classMap = new HashMap<>();
 
     public DexClassProvider(DexFile dexFile) {
         this.dexFile = dexFile;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/InlineMethodResolver.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/InlineMethodResolver.java
index 5e7322a..fbf5bce 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/InlineMethodResolver.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/InlineMethodResolver.java
@@ -30,15 +30,19 @@
 
 package com.android.tools.smali.dexlib2.analysis;
 
+import static java.util.Collections.unmodifiableList;
+
 import com.android.tools.smali.dexlib2.iface.Method;
 import com.android.tools.smali.dexlib2.iface.instruction.InlineIndexInstruction;
 import com.android.tools.smali.dexlib2.iface.instruction.VariableRegisterInstruction;
 import com.android.tools.smali.dexlib2.immutable.ImmutableMethod;
 import com.android.tools.smali.dexlib2.immutable.ImmutableMethodParameter;
 import com.android.tools.smali.dexlib2.immutable.util.ParamUtil;
-import com.google.common.collect.ImmutableList;
+import com.android.tools.smali.util.IteratorUtils;
 
 import javax.annotation.Nonnull;
+import java.util.ArrayList;
+import java.util.List;
 
 public abstract class InlineMethodResolver {
     // These are the possible values for the accessFlag field on a resolved inline method
@@ -65,7 +69,8 @@
     @Nonnull
     private static Method inlineMethod(int accessFlags, @Nonnull String cls, @Nonnull String name,
                                        @Nonnull String params, @Nonnull String returnType) {
-        ImmutableList<ImmutableMethodParameter> paramList = ImmutableList.copyOf(ParamUtil.parseParamString(params));
+        List<ImmutableMethodParameter> paramList = unmodifiableList(
+            IteratorUtils.toList(ParamUtil.parseParamString(params)));
         return new ImmutableMethod(cls, name, paramList, returnType, accessFlags, null, null, null);
     }
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/MethodAnalyzer.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/MethodAnalyzer.java
index b6174a2..3af6cb9 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/MethodAnalyzer.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/MethodAnalyzer.java
@@ -76,15 +76,15 @@
 import com.android.tools.smali.dexlib2.writer.util.TryListBuilder;
 import com.android.tools.smali.util.BitSetUtils;
 import com.android.tools.smali.util.ExceptionWithContext;
+import com.android.tools.smali.util.IteratorUtils;
 import com.android.tools.smali.util.SparseArray;
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.BitSet;
+import java.util.Collections;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * The MethodAnalyzer performs several functions. It "analyzes" the instructions and infers the register types
@@ -329,14 +329,8 @@
     }
 
     public List<Instruction> getInstructions() {
-        return Lists.transform(analyzedInstructions.getValues(), new Function<AnalyzedInstruction, Instruction>() {
-            @Nullable @Override public Instruction apply(@Nullable AnalyzedInstruction input) {
-                if (input == null) {
-                    return null;
-                }
-                return input.instruction;
-            }
-        });
+        return analyzedInstructions.getValues().stream().map(
+            input -> input == null ? null : input.instruction).collect(Collectors.toList());
     }
 
     @Nullable
@@ -458,7 +452,8 @@
     private void buildInstructionList() {
         int registerCount = methodImpl.getRegisterCount();
 
-        ImmutableList<Instruction> instructions = ImmutableList.copyOf(methodImpl.getInstructions());
+        List<Instruction> instructions = Collections.unmodifiableList(
+            IteratorUtils.toList(methodImpl.getInstructions()));
 
         analyzedInstructions.ensureCapacity(instructions.size());
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/PathEntryLoader.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/PathEntryLoader.java
index 3f65298..698eb1f 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/PathEntryLoader.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/PathEntryLoader.java
@@ -35,12 +35,12 @@
 import com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;
 import com.android.tools.smali.dexlib2.dexbacked.OatFile;
 import com.android.tools.smali.dexlib2.iface.MultiDexContainer;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
 
 import javax.annotation.Nonnull;
 import java.io.File;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
 
@@ -51,8 +51,8 @@
         return opcodes;
     }
 
-    final Set<File> loadedFiles = Sets.newHashSet();
-    final List<ClassProvider> classProviders = Lists.newArrayList();
+    final Set<File> loadedFiles = new HashSet<>();
+    final List<ClassProvider> classProviders = new ArrayList<>();
 
     public List<ClassProvider> getClassProviders() {
         return classProviders;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionClassDef.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionClassDef.java
index b140450..1451a26 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionClassDef.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionClassDef.java
@@ -35,11 +35,10 @@
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.iface.Field;
 import com.android.tools.smali.dexlib2.iface.Method;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterators;
+import com.android.tools.smali.util.ChainedIterator;
+import com.android.tools.smali.util.IteratorUtils;
+import com.android.tools.smali.util.TransformedIterator;
+
 import com.android.tools.smali.dexlib2.base.reference.BaseTypeReference;
 
 import javax.annotation.Nonnull;
@@ -48,8 +47,13 @@
 import java.lang.reflect.Modifier;
 import java.util.AbstractSet;
 import java.util.Iterator;
+import java.util.function.Function;
+import java.util.function.Predicate;
 import java.util.List;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.Arrays;
+import java.util.Collections;
 
 /**
  * Wraps a ClassDef around a class loaded in the current VM
@@ -79,17 +83,10 @@
         return ReflectionUtils.javaToDexName(superClass.getName());
     }
 
-    @Nonnull @Override public List<String> getInterfaces() {
-        return ImmutableList.copyOf(Iterators.transform(Iterators.forArray(cls.getInterfaces()), new Function<Class, String>() {
-            @Nullable
-            @Override
-            public String apply(@Nullable Class input) {
-                if (input == null) {
-                    return null;
-                }
-                return ReflectionUtils.javaToDexName(input.getName());
-            }
-        }));
+    @Nonnull @Override public List<String> getInterfaces() { 
+        return Arrays.asList(cls.getInterfaces()).stream().map(
+            i -> i == null ? null : ReflectionUtils.javaToDexName(i.getName()))
+            .collect(Collectors.toList());
     }
 
     @Nullable @Override public String getSourceFile() {
@@ -97,27 +94,25 @@
     }
 
     @Nonnull @Override public Set<? extends Annotation> getAnnotations() {
-        return ImmutableSet.of();
+        return Collections.emptySet();
     }
 
     @Nonnull @Override public Iterable<? extends Field> getStaticFields() {
         return new Iterable<Field>() {
             @Nonnull @Override public Iterator<Field> iterator() {
-                Iterator<java.lang.reflect.Field> staticFields = Iterators.filter(
-                        Iterators.forArray(cls.getDeclaredFields()),
+                Iterator<java.lang.reflect.Field> staticFields = IteratorUtils.filter(
+                        Arrays.asList(cls.getDeclaredFields()),
                         new Predicate<java.lang.reflect.Field>() {
-                            @Override public boolean apply(@Nullable java.lang.reflect.Field input) {
+                            @Override public boolean test(@Nullable java.lang.reflect.Field input) {
                                 return input!=null && Modifier.isStatic(input.getModifiers());
                             }
                         });
 
-                return Iterators.transform(staticFields,
-                        new Function<java.lang.reflect.Field, Field>() {
-                            @Nullable @Override public Field apply(@Nullable java.lang.reflect.Field input) {
-                                return new ReflectionField(input);
-                            }
-                        }
-                );
+                return new TransformedIterator<java.lang.reflect.Field, Field>(staticFields, new Function<java.lang.reflect.Field, Field>() {
+                    @Nullable @Override public Field apply(@Nullable java.lang.reflect.Field input) {
+                        return new ReflectionField(input);
+                    }
+                });
             }
         };
     }
@@ -125,15 +120,15 @@
     @Nonnull @Override public Iterable<? extends Field> getInstanceFields() {
         return new Iterable<Field>() {
             @Nonnull @Override public Iterator<Field> iterator() {
-                Iterator<java.lang.reflect.Field> staticFields = Iterators.filter(
-                        Iterators.forArray(cls.getDeclaredFields()),
+                Iterator<java.lang.reflect.Field> staticFields = IteratorUtils.filter(
+                        Arrays.asList(cls.getDeclaredFields()),
                         new Predicate<java.lang.reflect.Field>() {
-                            @Override public boolean apply(@Nullable java.lang.reflect.Field input) {
+                            @Override public boolean test(@Nullable java.lang.reflect.Field input) {
                                 return input!=null && !Modifier.isStatic(input.getModifiers());
                             }
                         });
 
-                return Iterators.transform(staticFields,
+                return new TransformedIterator<java.lang.reflect.Field, Field>(staticFields,
                         new Function<java.lang.reflect.Field, Field>() {
                             @Nullable @Override public Field apply(@Nullable java.lang.reflect.Field input) {
                                 return new ReflectionField(input);
@@ -147,7 +142,8 @@
     @Nonnull @Override public Set<? extends Field> getFields() {
         return new AbstractSet<Field>() {
             @Nonnull @Override public Iterator<Field> iterator() {
-                return Iterators.transform(Iterators.forArray(cls.getDeclaredFields()),
+                return new TransformedIterator<java.lang.reflect.Field, Field>(
+                    Arrays.asList(cls.getDeclaredFields()),
                         new Function<java.lang.reflect.Field, Field>() {
                             @Nullable @Override public Field apply(@Nullable java.lang.reflect.Field input) {
                                 return new ReflectionField(input);
@@ -166,28 +162,30 @@
         return new Iterable<Method>() {
             @Nonnull @Override public Iterator<Method> iterator() {
                 Iterator<Method> constructorIterator =
-                        Iterators.transform(Iterators.forArray(cls.getDeclaredConstructors()),
+                        new TransformedIterator<Constructor, Method>(
+                            Arrays.asList(cls.getDeclaredConstructors()).iterator(),
                                 new Function<Constructor, Method>() {
                                     @Nullable @Override public Method apply(@Nullable Constructor input) {
                                         return new ReflectionConstructor(input);
                                     }
                                 });
 
-                Iterator<java.lang.reflect.Method> directMethods = Iterators.filter(
-                        Iterators.forArray(cls.getDeclaredMethods()),
+                Iterator<java.lang.reflect.Method> directMethods = IteratorUtils.filter(
+                        Arrays.asList(cls.getDeclaredMethods()),
                         new Predicate<java.lang.reflect.Method>() {
-                            @Override public boolean apply(@Nullable java.lang.reflect.Method input) {
+                            @Override public boolean test(@Nullable java.lang.reflect.Method input) {
                                 return input != null && (input.getModifiers() & DIRECT_MODIFIERS) != 0;
                             }
                         });
 
-                Iterator<Method> methodIterator = Iterators.transform(directMethods,
+                Iterator<Method> methodIterator = new TransformedIterator<java.lang.reflect.Method, Method>(
+                    directMethods,
                         new Function<java.lang.reflect.Method, Method>() {
                             @Nullable @Override public Method apply(@Nullable java.lang.reflect.Method input) {
                                 return new ReflectionMethod(input);
                             }
                         });
-                return Iterators.concat(constructorIterator, methodIterator);
+                return new ChainedIterator<Method>(constructorIterator, methodIterator);
             }
         };
     }
@@ -195,15 +193,15 @@
     @Nonnull @Override public Iterable<? extends Method> getVirtualMethods() {
         return new Iterable<Method>() {
             @Nonnull @Override public Iterator<Method> iterator() {
-                Iterator<java.lang.reflect.Method> directMethods = Iterators.filter(
-                        Iterators.forArray(cls.getDeclaredMethods()),
+                Iterator<java.lang.reflect.Method> directMethods = IteratorUtils.filter(
+                        Arrays.asList(cls.getDeclaredMethods()),
                         new Predicate<java.lang.reflect.Method>() {
-                            @Override public boolean apply(@Nullable java.lang.reflect.Method input) {
+                            @Override public boolean test(@Nullable java.lang.reflect.Method input) {
                                 return input != null && (input.getModifiers() & DIRECT_MODIFIERS) == 0;
                             }
                         });
 
-                return Iterators.transform(directMethods,
+                return new TransformedIterator<java.lang.reflect.Method, Method>(directMethods,
                         new Function<java.lang.reflect.Method, Method>() {
                             @Nullable @Override public Method apply(@Nullable java.lang.reflect.Method input) {
                                 return new ReflectionMethod(input);
@@ -217,7 +215,8 @@
         return new AbstractSet<Method>() {
             @Nonnull @Override public Iterator<Method> iterator() {
                 Iterator<Method> constructorIterator =
-                        Iterators.transform(Iterators.forArray(cls.getDeclaredConstructors()),
+                        new TransformedIterator<Constructor, Method>(
+                            Arrays.asList(cls.getDeclaredConstructors()),
                                 new Function<Constructor, Method>() {
                                     @Nullable @Override public Method apply(@Nullable Constructor input) {
                                         return new ReflectionConstructor(input);
@@ -225,13 +224,14 @@
                                 });
 
                 Iterator<Method> methodIterator =
-                        Iterators.transform(Iterators.forArray(cls.getDeclaredMethods()),
+                        new TransformedIterator<java.lang.reflect.Method, Method>(
+                            Arrays.asList(cls.getDeclaredMethods()),
                                 new Function<java.lang.reflect.Method, Method>() {
                                     @Nullable @Override public Method apply(@Nullable java.lang.reflect.Method input) {
                                         return new ReflectionMethod(input);
                                     }
                                 });
-                return Iterators.concat(constructorIterator, methodIterator);
+                return new ChainedIterator<Method>(constructorIterator, methodIterator);
             }
 
             @Override public int size() {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionConstructor.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionConstructor.java
index 80ba4be..ff11239 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionConstructor.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionConstructor.java
@@ -37,13 +37,13 @@
 import com.android.tools.smali.dexlib2.iface.Method;
 import com.android.tools.smali.dexlib2.iface.MethodImplementation;
 import com.android.tools.smali.dexlib2.iface.MethodParameter;
-import com.google.common.collect.ImmutableSet;
 import com.android.tools.smali.dexlib2.base.reference.BaseMethodReference;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.lang.reflect.Constructor;
 import java.util.AbstractList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -62,7 +62,7 @@
             @Override public MethodParameter get(final int index) {
                 return new BaseMethodParameter() {
                     @Nonnull @Override public Set<? extends Annotation> getAnnotations() {
-                        return ImmutableSet.of();
+                        return Collections.emptySet();
                     }
 
                     @Nullable @Override public String getName() {
@@ -86,7 +86,7 @@
     }
 
     @Nonnull @Override public Set<? extends Annotation> getAnnotations() {
-        return ImmutableSet.of();
+        return Collections.emptySet();
     }
 
     @Nullable @Override public MethodImplementation getImplementation() {
@@ -120,6 +120,6 @@
     }
 
     @Nonnull @Override public Set<HiddenApiRestriction> getHiddenApiRestrictions() {
-        return ImmutableSet.of();
+        return Collections.emptySet();
     }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionField.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionField.java
index d35f90d..5205ea0 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionField.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionField.java
@@ -34,12 +34,12 @@
 import com.android.tools.smali.dexlib2.analysis.reflection.util.ReflectionUtils;
 import com.android.tools.smali.dexlib2.iface.Annotation;
 import com.android.tools.smali.dexlib2.iface.Field;
-import com.google.common.collect.ImmutableSet;
 import com.android.tools.smali.dexlib2.base.reference.BaseFieldReference;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.Collections;
 import java.util.Set;
 
 public class ReflectionField extends BaseFieldReference implements Field {
@@ -58,7 +58,7 @@
     }
 
     @Nonnull @Override public Set<? extends Annotation> getAnnotations() {
-        return ImmutableSet.of();
+        return Collections.emptySet();
     }
 
     @Nonnull @Override public String getDefiningClass() {
@@ -74,6 +74,6 @@
     }
 
     @Nonnull @Override public Set<HiddenApiRestriction> getHiddenApiRestrictions() {
-        return ImmutableSet.of();
+        return Collections.emptySet();
     }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionMethod.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionMethod.java
index 24396b1..40f5d4a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionMethod.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/ReflectionMethod.java
@@ -37,12 +37,12 @@
 import com.android.tools.smali.dexlib2.iface.Method;
 import com.android.tools.smali.dexlib2.iface.MethodImplementation;
 import com.android.tools.smali.dexlib2.iface.MethodParameter;
-import com.google.common.collect.ImmutableSet;
 import com.android.tools.smali.dexlib2.base.reference.BaseMethodReference;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.AbstractList;
+import java.util.Collections;
 import java.util.List;
 import java.util.Set;
 
@@ -61,7 +61,7 @@
             @Override public MethodParameter get(final int index) {
                 return new BaseMethodParameter() {
                     @Nonnull @Override public Set<? extends Annotation> getAnnotations() {
-                        return ImmutableSet.of();
+                        return Collections.emptySet();
                     }
 
                     @Nullable @Override public String getName() {
@@ -85,7 +85,7 @@
     }
 
     @Nonnull @Override public Set<? extends Annotation> getAnnotations() {
-        return ImmutableSet.of();
+        return Collections.emptySet();
     }
 
     @Nullable @Override public MethodImplementation getImplementation() {
@@ -119,6 +119,6 @@
     }
 
     @Nonnull @Override public Set<HiddenApiRestriction> getHiddenApiRestrictions() {
-        return ImmutableSet.of();
+        return Collections.emptySet();
     }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/util/ReflectionUtils.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/util/ReflectionUtils.java
index 2fb8bdc..ab4a289 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/util/ReflectionUtils.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/reflection/util/ReflectionUtils.java
@@ -30,21 +30,39 @@
 
 package com.android.tools.smali.dexlib2.analysis.reflection.util;
 
-import com.google.common.collect.ImmutableBiMap;
+import static java.util.Collections.unmodifiableMap;
+
+import java.util.Map;
+import java.util.HashMap;
 
 public class ReflectionUtils {
 
-    private static ImmutableBiMap<String, String> primitiveMap = ImmutableBiMap.<String, String>builder()
-            .put("boolean", "Z")
-            .put("int", "I")
-            .put("long", "J")
-            .put("double", "D")
-            .put("void", "V")
-            .put("float", "F")
-            .put("char", "C")
-            .put("short", "S")
-            .put("byte", "B")
-            .build();
+    private static Map<String, String> primitiveMap;
+    
+    static {
+        Map<String, String> temp = new HashMap<>();
+            temp.put("boolean", "Z");
+            temp.put("int", "I");
+            temp.put("long", "J");
+            temp.put("double", "D");
+            temp.put("void", "V");
+            temp.put("float", "F");
+            temp.put("char", "C");
+            temp.put("short", "S");
+            temp.put("byte", "B");
+            primitiveMap = unmodifiableMap(temp);
+    }
+
+    private static Map<String, String> primitiveMapInverse = getInverse();
+
+    private static Map<String, String> getInverse() {
+        Map<String, String> temp = new HashMap<>();
+        for (Map.Entry<String, String> entry : primitiveMap.entrySet()) {
+            temp.put(entry.getValue(), entry.getKey());
+        }
+        return unmodifiableMap(temp);
+    }
+
 
     public static String javaToDexName(String javaName) {
         if (javaName.charAt(0) == '[') {
@@ -63,8 +81,8 @@
             return dexName.replace('/', '.');
         }
 
-        if (primitiveMap.inverse().containsKey(dexName)) {
-            return primitiveMap.inverse().get(dexName);
+        if (primitiveMapInverse.containsKey(dexName)) {
+            return primitiveMapInverse.get(dexName);
         }
 
         return dexName.replace('/', '.').substring(1, dexName.length()-1);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/util/LruCache.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/util/LruCache.java
new file mode 100644
index 0000000..5c97189
--- /dev/null
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/util/LruCache.java
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2024, Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.tools.smali.dexlib2.analysis.util;
+
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+
+/**
+ * Based on android.util.LruCache.
+ * A cache that holds strong references to a limited number of values. Each time
+ * a value is accessed, it is moved to the head of a queue. When a value is
+ * added to a full cache, the value at the end of that queue is evicted and may
+ * become eligible for garbage collection.
+ *
+ * <p>If your cached values hold resources that need to be explicitly released,
+ * override {@link #entryRemoved}.
+ *
+ * <p>If a cache miss should be computed on demand for the corresponding keys,
+ * override {@link #create}. This simplifies the calling code, allowing it to
+ * assume a value will always be returned, even when there's a cache miss.
+ *
+ * <p>By default, the cache size is measured in the number of entries. Override
+ * {@link #sizeOf} to size the cache in different units. For example, this cache
+ * is limited to 4MiB of bitmaps:
+ * <pre>   {@code
+ *   int cacheSize = 4 * 1024 * 1024; // 4MiB
+ *   LruCache<String, Bitmap> bitmapCache = new LruCache<String, Bitmap>(cacheSize) {
+ *       protected int sizeOf(String key, Bitmap value) {
+ *           return value.getByteCount();
+ *       }
+ *   }}</pre>
+ *
+ * <p>This class is thread-safe. Perform multiple cache operations atomically by
+ * synchronizing on the cache: <pre>   {@code
+ *   synchronized (cache) {
+ *     if (cache.get(key) == null) {
+ *         cache.put(key, value);
+ *     }
+ *   }}</pre>
+ *
+ * <p>This class does not allow null to be used as a key or value. A return
+ * value of null from {@link #get}, {@link #put} or {@link #remove} is
+ * unambiguous: the key was not in the cache.
+ */
+
+public class LruCache<K, V> {
+    private final LinkedHashMap<K, V> map;
+
+    /** Size of this cache in units. Not necessarily the number of elements. */
+    private int size;
+    private int maxSize;
+
+    private int putCount;
+    private int createCount;
+    private int evictionCount;
+    private int hitCount;
+    private int missCount;
+
+    /**
+     * @param maxSize for caches that do not override {@link #sizeOf}, this is
+     *     the maximum number of entries in the cache. For all other caches,
+     *     this is the maximum sum of the sizes of the entries in this cache.
+     */
+    public LruCache(int maxSize) {
+        if (maxSize <= 0) {
+            throw new IllegalArgumentException("maxSize <= 0");
+        }
+        this.maxSize = maxSize;
+        this.map = new LinkedHashMap<K, V>(0, 0.75f, true);
+    }
+
+    /**
+     * Sets the size of the cache.
+     *
+     * @param maxSize The new maximum size.
+     */
+    public void resize(int maxSize) {
+        if (maxSize <= 0) {
+            throw new IllegalArgumentException("maxSize <= 0");
+        }
+
+        synchronized (this) {
+            this.maxSize = maxSize;
+        }
+        trimToSize(maxSize);
+    }
+
+    /**
+     * Returns the value for {@code key} if it exists in the cache or can be
+     * created by {@code #create}. If a value was returned, it is moved to the
+     * head of the queue. This returns null if a value is not cached and cannot
+     * be created.
+     */
+    public final V get(K key) {
+        if (key == null) {
+            throw new NullPointerException("key == null");
+        }
+
+        V mapValue;
+        synchronized (this) {
+            mapValue = map.get(key);
+            if (mapValue != null) {
+                hitCount++;
+                return mapValue;
+            }
+            missCount++;
+        }
+
+        /*
+         * Attempt to create a value. This may take a long time, and the map
+         * may be different when create() returns. If a conflicting value was
+         * added to the map while create() was working, we leave that value in
+         * the map and release the created value.
+         */
+
+        V createdValue = create(key);
+        if (createdValue == null) {
+            return null;
+        }
+
+        synchronized (this) {
+            createCount++;
+            mapValue = map.put(key, createdValue);
+
+            if (mapValue != null) {
+                // There was a conflict so undo that last put
+                map.put(key, mapValue);
+            } else {
+                size += safeSizeOf(key, createdValue);
+            }
+        }
+
+        if (mapValue != null) {
+            entryRemoved(false, key, createdValue, mapValue);
+            return mapValue;
+        } else {
+            trimToSize(maxSize);
+            return createdValue;
+        }
+    }
+
+    /**
+     * Caches {@code value} for {@code key}. The value is moved to the head of
+     * the queue.
+     *
+     * @return the previous value mapped by {@code key}.
+     */
+    public final V put(K key, V value) {
+        if (key == null || value == null) {
+            throw new NullPointerException("key == null || value == null");
+        }
+
+        V previous;
+        synchronized (this) {
+            putCount++;
+            size += safeSizeOf(key, value);
+            previous = map.put(key, value);
+            if (previous != null) {
+                size -= safeSizeOf(key, previous);
+            }
+        }
+
+        if (previous != null) {
+            entryRemoved(false, key, previous, value);
+        }
+
+        trimToSize(maxSize);
+        return previous;
+    }
+
+    /**
+     * Remove the eldest entries until the total of remaining entries is at or
+     * below the requested size.
+     *
+     * @param maxSize the maximum size of the cache before returning. May be -1
+     *            to evict even 0-sized elements.
+     */
+    public void trimToSize(int maxSize) {
+        while (true) {
+            K key;
+            V value;
+            synchronized (this) {
+                if (size < 0 || (map.isEmpty() && size != 0)) {
+                    throw new IllegalStateException(getClass().getName()
+                            + ".sizeOf() is reporting inconsistent results!");
+                }
+
+                if (size <= maxSize) {
+                    break;
+                }
+
+                Map.Entry<K, V> toEvict = eldest();
+                if (toEvict == null) {
+                    break;
+                }
+
+                key = toEvict.getKey();
+                value = toEvict.getValue();
+                map.remove(key);
+                size -= safeSizeOf(key, value);
+                evictionCount++;
+            }
+
+            entryRemoved(true, key, value, null);
+        }
+    }
+
+
+    private Map.Entry<K, V> eldest() {
+        final Iterator<Map.Entry<K, V>> it = map.entrySet().iterator();
+        return it.hasNext() ? it.next() : null;
+    }
+
+    /**
+     * Removes the entry for {@code key} if it exists.
+     *
+     * @return the previous value mapped by {@code key}.
+     */
+    public final V remove(K key) {
+        if (key == null) {
+            throw new NullPointerException("key == null");
+        }
+
+        V previous;
+        synchronized (this) {
+            previous = map.remove(key);
+            if (previous != null) {
+                size -= safeSizeOf(key, previous);
+            }
+        }
+
+        if (previous != null) {
+            entryRemoved(false, key, previous, null);
+        }
+
+        return previous;
+    }
+
+    /**
+     * Called for entries that have been evicted or removed. This method is
+     * invoked when a value is evicted to make space, removed by a call to
+     * {@link #remove}, or replaced by a call to {@link #put}. The default
+     * implementation does nothing.
+     *
+     * <p>The method is called without synchronization: other threads may
+     * access the cache while this method is executing.
+     *
+     * @param evicted true if the entry is being removed to make space, false
+     *     if the removal was caused by a {@link #put} or {@link #remove}.
+     * @param newValue the new value for {@code key}, if it exists. If non-null,
+     *     this removal was caused by a {@link #put} or a {@link #get}. Otherwise it was caused by
+     *     an eviction or a {@link #remove}.
+     */
+    protected void entryRemoved(boolean evicted, K key, V oldValue, V newValue) {}
+
+    /**
+     * Called after a cache miss to compute a value for the corresponding key.
+     * Returns the computed value or null if no value can be computed. The
+     * default implementation returns null.
+     *
+     * <p>The method is called without synchronization: other threads may
+     * access the cache while this method is executing.
+     *
+     * <p>If a value for {@code key} exists in the cache when this method
+     * returns, the created value will be released with {@link #entryRemoved}
+     * and discarded. This can occur when multiple threads request the same key
+     * at the same time (causing multiple values to be created), or when one
+     * thread calls {@link #put} while another is creating a value for the same
+     * key.
+     */
+    protected V create(K key) {
+        return null;
+    }
+
+    private int safeSizeOf(K key, V value) {
+        int result = sizeOf(key, value);
+        if (result < 0) {
+            throw new IllegalStateException("Negative size: " + key + "=" + value);
+        }
+        return result;
+    }
+
+    /**
+     * Returns the size of the entry for {@code key} and {@code value} in
+     * user-defined units.  The default implementation returns 1 so that size
+     * is the number of entries and max size is the maximum number of entries.
+     *
+     * <p>An entry's size must not change while it is in the cache.
+     */
+    protected int sizeOf(K key, V value) {
+        return 1;
+    }
+
+    /**
+     * Clear the cache, calling {@link #entryRemoved} on each removed entry.
+     */
+    public final void evictAll() {
+        trimToSize(-1); // -1 will evict 0-sized elements
+    }
+
+    /**
+     * For caches that do not override {@link #sizeOf}, this returns the number
+     * of entries in the cache. For all other caches, this returns the sum of
+     * the sizes of the entries in this cache.
+     */
+    public synchronized final int size() {
+        return size;
+    }
+
+    /**
+     * For caches that do not override {@link #sizeOf}, this returns the maximum
+     * number of entries in the cache. For all other caches, this returns the
+     * maximum sum of the sizes of the entries in this cache.
+     */
+    public synchronized final int maxSize() {
+        return maxSize;
+    }
+
+    /**
+     * Returns the number of times {@link #get} returned a value that was
+     * already present in the cache.
+     */
+    public synchronized final int hitCount() {
+        return hitCount;
+    }
+
+    /**
+     * Returns the number of times {@link #get} returned null or required a new
+     * value to be created.
+     */
+    public synchronized final int missCount() {
+        return missCount;
+    }
+
+    /**
+     * Returns the number of times {@link #create(Object)} returned a value.
+     */
+    public synchronized final int createCount() {
+        return createCount;
+    }
+
+    /**
+     * Returns the number of times {@link #put} was called.
+     */
+    public synchronized final int putCount() {
+        return putCount;
+    }
+
+    /**
+     * Returns the number of values that have been evicted.
+     */
+    public synchronized final int evictionCount() {
+        return evictionCount;
+    }
+
+    /**
+     * Returns a copy of the current contents of the cache, ordered from least
+     * recently accessed to most recently accessed.
+     */
+    public synchronized final Map<K, V> snapshot() {
+        return new LinkedHashMap<K, V>(map);
+    }
+
+    @Override public synchronized final String toString() {
+        int accesses = hitCount + missCount;
+        int hitPercent = accesses != 0 ? (100 * hitCount / accesses) : 0;
+        return String.format("LruCache[maxSize=%d,hits=%d,misses=%d,hitRate=%d%%]",
+                maxSize, hitCount, missCount, hitPercent);
+    }
+}
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/util/MemoizingSupplier.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/util/MemoizingSupplier.java
new file mode 100644
index 0000000..c9622f1
--- /dev/null
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/analysis/util/MemoizingSupplier.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2024, Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.tools.smali.dexlib2.analysis.util;
+
+import java.util.function.Supplier;
+
+/** 
+ * Based on Guava's NonSerializableMemoizing Supplier. This implementation is thread safe.
+ */
+public class MemoizingSupplier<T> implements Supplier<T> {
+    // Delegate will only be null when the value was successfuly computed
+    private volatile Supplier<T> delegate;
+    private T value;
+
+    private MemoizingSupplier(Supplier<T> delegate) {
+        if (delegate == null) {
+            throw new NullPointerException("delegate == null");
+        }
+        this.delegate = delegate;
+    }
+
+    @Override
+    public T get() {
+        // Because Supplier is read-heavy, we use the "double-checked locking" pattern.
+        if (delegate != null) {
+            synchronized (this) {
+                if (delegate != null) {
+                    T t = delegate.get();
+                    value = t;
+                    delegate = null;
+                }
+            }
+        }
+        // This is safe because we checked `delegate.`
+        return value;
+    }
+
+    public static <T extends Object> MemoizingSupplier<T> memoize(Supplier<T> delegate) {
+        if (delegate instanceof MemoizingSupplier) {
+            return (MemoizingSupplier<T>) delegate;
+        }
+        return new MemoizingSupplier<>(delegate);
+    }
+}
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/BuilderTryBlock.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/BuilderTryBlock.java
index 25c079d..19c05b1 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/BuilderTryBlock.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/BuilderTryBlock.java
@@ -30,12 +30,13 @@
 
 package com.android.tools.smali.dexlib2.builder;
 
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.base.BaseTryBlock;
 import com.android.tools.smali.dexlib2.iface.reference.TypeReference;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 public class BuilderTryBlock extends BaseTryBlock<BuilderExceptionHandler> {
@@ -75,6 +76,6 @@
     }
 
     @Nonnull @Override public List<? extends BuilderExceptionHandler> getExceptionHandlers() {
-        return ImmutableList.of(exceptionHandler);
+        return Collections.unmodifiableList(Arrays.asList(exceptionHandler));
     }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/LocatedItems.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/LocatedItems.java
index 6adf69e..9060713 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/LocatedItems.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/LocatedItems.java
@@ -30,10 +30,9 @@
 
 package com.android.tools.smali.dexlib2.builder;
 
-import com.google.common.collect.ImmutableList;
-
 import java.util.AbstractSet;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
@@ -50,7 +49,7 @@
     @Nonnull
     private List<T> getItems() {
         if (items == null) {
-            return ImmutableList.of();
+            return Collections.emptyList();
         }
         return items;
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/MutableMethodImplementation.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/MutableMethodImplementation.java
index 2be0f22..40f9dd7 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/MutableMethodImplementation.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/MutableMethodImplementation.java
@@ -122,11 +122,6 @@
 import com.android.tools.smali.dexlib2.iface.instruction.formats.SparseSwitchPayload;
 import com.android.tools.smali.dexlib2.iface.reference.TypeReference;
 import com.android.tools.smali.util.ExceptionWithContext;
-import com.google.common.base.Function;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
-
 import java.util.AbstractList;
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -138,8 +133,9 @@
 
 public class MutableMethodImplementation implements MethodImplementation {
     private final int registerCount;
-    final ArrayList<MethodLocation> instructionList = Lists.newArrayList(new MethodLocation(null, 0, 0));
-    private final ArrayList<BuilderTryBlock> tryBlocks = Lists.newArrayList();
+    final ArrayList<MethodLocation> instructionList = new ArrayList<>(
+        Arrays.asList(new MethodLocation(null, 0, 0)));
+    private final ArrayList<BuilderTryBlock> tryBlocks = new ArrayList<>();
     private boolean fixInstructions = true;
 
     public MutableMethodImplementation(@Nonnull MethodImplementation methodImplementation) {
@@ -162,7 +158,7 @@
             codeAddressToIndex[instructionList.get(i).codeAddress] = i;
         }
 
-        List<Task> switchPayloadTasks = Lists.newArrayList();
+        List<Task> switchPayloadTasks = new ArrayList<>();
         index = 0;
         for (final Instruction instruction: methodImplementation.getInstructions()) {
             final MethodLocation location = instructionList.get(index);
@@ -256,17 +252,20 @@
         if (fixInstructions) {
             fixInstructions();
         }
-        return Iterables.concat(
-                Iterables.transform(instructionList, new Function<MethodLocation, Iterable<? extends DebugItem>>() {
-                    @Nullable @Override public Iterable<? extends DebugItem> apply(@Nullable MethodLocation input) {
-                        assert input != null;
-                        if (fixInstructions) {
-                            throw new IllegalStateException("This iterator was invalidated by a change to" +
-                                    " this MutableMethodImplementation.");
-                        }
-                        return input.getDebugItems();
-                    }
-                }));
+
+        ArrayList<DebugItem> debugItems = new ArrayList<>();
+
+        for (MethodLocation methodLocation: instructionList) {
+            assert methodLocation != null;
+
+            if (fixInstructions) {
+                throw new IllegalStateException("This iterator was invalidated by a change to" +
+                            " this MutableMethodImplementation.");
+            }
+            debugItems.addAll(methodLocation.getDebugItems());
+        }
+
+        return Collections.unmodifiableList(debugItems);
     }
 
     public void addCatch(@Nullable TypeReference type, @Nonnull Label from,
@@ -438,7 +437,7 @@
     }
 
     private void fixInstructions() {
-        HashSet<MethodLocation> payloadLocations = Sets.newHashSet();
+        HashSet<MethodLocation> payloadLocations = new HashSet<>();
 
         for (MethodLocation location: instructionList) {
             BuilderInstruction instruction = location.instruction;
@@ -1104,7 +1103,7 @@
             baseAddress = switchLocation.codeAddress;
         }
 
-        List<Label> labels = Lists.newArrayList();
+        List<Label> labels = new ArrayList<>();
         for (SwitchElement element: switchElements) {
             labels.add(newLabel(codeAddressToIndex, element.getOffset() + baseAddress));
         }
@@ -1129,7 +1128,7 @@
             baseAddress = switchLocation.codeAddress;
         }
 
-        List<SwitchLabelElement> labelElements = Lists.newArrayList();
+        List<SwitchLabelElement> labelElements = new ArrayList<>();
         for (SwitchElement element: switchElements) {
             labelElements.add(new SwitchLabelElement(element.getKey(),
                     newLabel(codeAddressToIndex, element.getOffset() + baseAddress)));
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/instruction/BuilderArrayPayload.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/instruction/BuilderArrayPayload.java
index a42ee87..d3cc40c 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/instruction/BuilderArrayPayload.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/instruction/BuilderArrayPayload.java
@@ -34,10 +34,10 @@
 import com.android.tools.smali.dexlib2.Opcode;
 import com.android.tools.smali.dexlib2.builder.BuilderInstruction;
 import com.android.tools.smali.dexlib2.iface.instruction.formats.ArrayPayload;
-import com.google.common.collect.ImmutableList;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.Collections;
 import java.util.List;
 
 public class BuilderArrayPayload extends BuilderInstruction implements ArrayPayload {
@@ -50,7 +50,7 @@
                                @Nullable List<Number> arrayElements) {
         super(OPCODE);
         this.elementWidth = elementWidth;
-        this.arrayElements = arrayElements==null?ImmutableList.<Number>of():arrayElements;
+        this.arrayElements = arrayElements == null ? Collections.emptyList() : arrayElements;
     }
 
     @Override public int getElementWidth() { return elementWidth; }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/instruction/BuilderPackedSwitchPayload.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/instruction/BuilderPackedSwitchPayload.java
index cac3350..fd872d1 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/instruction/BuilderPackedSwitchPayload.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/instruction/BuilderPackedSwitchPayload.java
@@ -35,11 +35,12 @@
 import com.android.tools.smali.dexlib2.builder.BuilderSwitchPayload;
 import com.android.tools.smali.dexlib2.builder.Label;
 import com.android.tools.smali.dexlib2.iface.instruction.formats.PackedSwitchPayload;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 public class BuilderPackedSwitchPayload extends BuilderSwitchPayload implements
@@ -52,9 +53,9 @@
                                       @Nullable List<? extends Label> switchElements) {
         super(OPCODE);
         if (switchElements == null) {
-            this.switchElements = ImmutableList.of();
+            this.switchElements = Collections.emptyList();
         } else {
-            this.switchElements = Lists.newArrayList();
+            this.switchElements = new ArrayList<>();
             int key = startKey;
             for (Label target: switchElements) {
                 this.switchElements.add(new BuilderSwitchElement(this, key++, target));
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/instruction/BuilderSparseSwitchPayload.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/instruction/BuilderSparseSwitchPayload.java
index 6b4c021..b1e935c 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/instruction/BuilderSparseSwitchPayload.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/builder/instruction/BuilderSparseSwitchPayload.java
@@ -35,13 +35,13 @@
 import com.android.tools.smali.dexlib2.builder.BuilderSwitchPayload;
 import com.android.tools.smali.dexlib2.builder.SwitchLabelElement;
 import com.android.tools.smali.dexlib2.iface.instruction.formats.SparseSwitchPayload;
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.Collections;
 import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 public class BuilderSparseSwitchPayload extends BuilderSwitchPayload implements
     SparseSwitchPayload {
@@ -52,14 +52,14 @@
     public BuilderSparseSwitchPayload(@Nullable List<? extends SwitchLabelElement> switchElements) {
         super(OPCODE);
         if (switchElements == null) {
-            this.switchElements = ImmutableList.of();
+            this.switchElements = Collections.emptyList();
         } else {
-            this.switchElements = Lists.transform(switchElements, new Function<SwitchLabelElement, BuilderSwitchElement>() {
+            this.switchElements = switchElements.stream().map(new Function<SwitchLabelElement, BuilderSwitchElement>() {
                 @Nullable @Override public BuilderSwitchElement apply(@Nullable SwitchLabelElement element) {
                     assert element != null;
                     return new BuilderSwitchElement(BuilderSparseSwitchPayload.this, element.key, element.target);
                 }
-            });
+            }).collect(Collectors.toList());
         }
     }
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedMethod.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedMethod.java
index 84e6e83..3e0327e 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedMethod.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/DexBackedMethod.java
@@ -155,7 +155,7 @@
                 }
             };
         }
-        return unmodifiableList(List.of());
+        return Collections.emptyList();
     }
 
     @Nonnull
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/OatFile.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/OatFile.java
index a6011b4..8b41ab8 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/OatFile.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/OatFile.java
@@ -170,11 +170,11 @@
     @Nonnull
     public List<String> getBootClassPath() {
         if (getOatVersion() < 75) {
-            return Collections.unmodifiableList(List.of());
+            return Collections.emptyList();
         }
         String bcp = oatHeader.getKeyValue("bootclasspath");
         if (bcp == null) {
-            return Collections.unmodifiableList(List.of());
+            return Collections.emptyList();
         }
         return Arrays.asList(bcp.split(":"));
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java
index ec93d9a..da4996b 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/dexbacked/instruction/DexBackedArrayPayload.java
@@ -81,7 +81,7 @@
         }
 
         if (elementCount == 0) {
-            return Collections.unmodifiableList(List.of());
+            return Collections.emptyList();
         }
 
         switch (elementWidth) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableAnnotation.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableAnnotation.java
index 7168c39..ca55368 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableAnnotation.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableAnnotation.java
@@ -35,16 +35,16 @@
 import com.android.tools.smali.dexlib2.iface.AnnotationElement;
 import com.android.tools.smali.util.ImmutableConverter;
 import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableSet;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Collection;
+import java.util.Set;
 
 public class ImmutableAnnotation extends BaseAnnotation {
     protected final int visibility;
     @Nonnull protected final String type;
-    @Nonnull protected final ImmutableSet<? extends ImmutableAnnotationElement> elements;
+    @Nonnull protected final Set<? extends ImmutableAnnotationElement> elements;
 
     public ImmutableAnnotation(int visibility,
                                @Nonnull String type,
@@ -56,7 +56,7 @@
 
     public ImmutableAnnotation(int visibility,
                                @Nonnull String type,
-                               @Nullable ImmutableSet<? extends ImmutableAnnotationElement> elements) {
+                               @Nullable Set<? extends ImmutableAnnotationElement> elements) {
         this.visibility = visibility;
         this.type = type;
         this.elements = ImmutableUtils.nullToEmptySet(elements);
@@ -74,10 +74,10 @@
 
     @Override public int getVisibility() { return visibility; }
     @Nonnull @Override public String getType() { return type; }
-    @Nonnull @Override public ImmutableSet<? extends ImmutableAnnotationElement> getElements() { return elements; }
+    @Nonnull @Override public Set<? extends ImmutableAnnotationElement> getElements() { return elements; }
 
     @Nonnull
-    public static ImmutableSet<ImmutableAnnotation> immutableSetOf(@Nullable Iterable<? extends Annotation> list) {
+    public static Set<ImmutableAnnotation> immutableSetOf(@Nullable Iterable<? extends Annotation> list) {
         return CONVERTER.toSet(list);
     }
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableAnnotationElement.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableAnnotationElement.java
index b589b1a..bb2731e 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableAnnotationElement.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableAnnotationElement.java
@@ -36,10 +36,10 @@
 import com.android.tools.smali.dexlib2.immutable.value.ImmutableEncodedValue;
 import com.android.tools.smali.dexlib2.immutable.value.ImmutableEncodedValueFactory;
 import com.android.tools.smali.util.ImmutableConverter;
-import com.google.common.collect.ImmutableSet;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.Set;
 
 public class ImmutableAnnotationElement extends BaseAnnotationElement {
     @Nonnull protected final String name;
@@ -70,7 +70,7 @@
     @Nonnull @Override public EncodedValue getValue() { return value; }
 
     @Nonnull
-    public static ImmutableSet<ImmutableAnnotationElement> immutableSetOf(
+    public static Set<ImmutableAnnotationElement> immutableSetOf(
             @Nullable Iterable<? extends AnnotationElement> list) {
         return CONVERTER.toSet(list);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableClassDef.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableClassDef.java
index 7f70a4a..34298cd 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableClassDef.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableClassDef.java
@@ -30,6 +30,8 @@
 
 package com.android.tools.smali.dexlib2.immutable;
 
+import static java.util.Collections.unmodifiableList;
+
 import com.android.tools.smali.dexlib2.base.reference.BaseTypeReference;
 import com.android.tools.smali.dexlib2.iface.Annotation;
 import com.android.tools.smali.dexlib2.iface.ClassDef;
@@ -37,31 +39,32 @@
 import com.android.tools.smali.dexlib2.iface.Method;
 import com.android.tools.smali.dexlib2.util.FieldUtil;
 import com.android.tools.smali.dexlib2.util.MethodUtil;
+import com.android.tools.smali.util.ChainedIterator;
 import com.android.tools.smali.util.ImmutableConverter;
 import com.android.tools.smali.util.ImmutableUtils;
+import com.android.tools.smali.util.IteratorUtils;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Iterators;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
-import java.util.AbstractCollection;
+import java.util.ArrayList;
 import java.util.Collection;
-import java.util.Iterator;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
+
 
 public class ImmutableClassDef extends BaseTypeReference implements ClassDef {
     @Nonnull protected final String type;
     protected final int accessFlags;
     @Nullable protected final String superclass;
-    @Nonnull protected final ImmutableList<String> interfaces;
+    @Nonnull protected final List<String> interfaces;
     @Nullable protected final String sourceFile;
-    @Nonnull protected final ImmutableSet<? extends ImmutableAnnotation> annotations;
-    @Nonnull protected final ImmutableSortedSet<? extends ImmutableField> staticFields;
-    @Nonnull protected final ImmutableSortedSet<? extends ImmutableField> instanceFields;
-    @Nonnull protected final ImmutableSortedSet<? extends ImmutableMethod> directMethods;
-    @Nonnull protected final ImmutableSortedSet<? extends ImmutableMethod> virtualMethods;
+    @Nonnull protected final Set<? extends ImmutableAnnotation> annotations;
+    @Nonnull protected final SortedSet<? extends ImmutableField> staticFields;
+    @Nonnull protected final SortedSet<? extends ImmutableField> instanceFields;
+    @Nonnull protected final SortedSet<? extends ImmutableMethod> directMethods;
+    @Nonnull protected final SortedSet<? extends ImmutableMethod> virtualMethods;
 
     public ImmutableClassDef(@Nonnull String type,
                              int accessFlags,
@@ -72,22 +75,22 @@
                              @Nullable Iterable<? extends Field> fields,
                              @Nullable Iterable<? extends Method> methods) {
         if (fields == null) {
-            fields = ImmutableList.of();
+            fields = Collections.emptyList();
         }
         if (methods == null) {
-            methods = ImmutableList.of();
+            methods = Collections.emptyList();
         }
 
         this.type = type;
         this.accessFlags = accessFlags;
         this.superclass = superclass;
-        this.interfaces = interfaces==null ? ImmutableList.<String>of() : ImmutableList.copyOf(interfaces);
+        this.interfaces = interfaces == null ? Collections.emptyList() : unmodifiableList(new ArrayList<>(interfaces));
         this.sourceFile = sourceFile;
         this.annotations = ImmutableAnnotation.immutableSetOf(annotations);
-        this.staticFields = ImmutableField.immutableSetOf(Iterables.filter(fields, FieldUtil.FIELD_IS_STATIC));
-        this.instanceFields = ImmutableField.immutableSetOf(Iterables.filter(fields, FieldUtil.FIELD_IS_INSTANCE));
-        this.directMethods = ImmutableMethod.immutableSetOf(Iterables.filter(methods, MethodUtil.METHOD_IS_DIRECT));
-        this.virtualMethods = ImmutableMethod.immutableSetOf(Iterables.filter(methods, MethodUtil.METHOD_IS_VIRTUAL));
+        this.staticFields = ImmutableField.immutableSetOf(IteratorUtils.filter(fields, FieldUtil.FIELD_IS_STATIC));
+        this.instanceFields = ImmutableField.immutableSetOf(IteratorUtils.filter(fields, FieldUtil.FIELD_IS_INSTANCE));
+        this.directMethods = ImmutableMethod.immutableSetOf(IteratorUtils.filter(methods, MethodUtil.METHOD_IS_DIRECT));
+        this.virtualMethods = ImmutableMethod.immutableSetOf(IteratorUtils.filter(methods, MethodUtil.METHOD_IS_VIRTUAL));
     }
 
     public ImmutableClassDef(@Nonnull String type,
@@ -103,7 +106,7 @@
         this.type = type;
         this.accessFlags = accessFlags;
         this.superclass = superclass;
-        this.interfaces = interfaces==null ? ImmutableList.<String>of() : ImmutableList.copyOf(interfaces);
+        this.interfaces = interfaces == null ? Collections.emptyList() : unmodifiableList(new ArrayList<>(interfaces));
         this.sourceFile = sourceFile;
         this.annotations = ImmutableAnnotation.immutableSetOf(annotations);
         this.staticFields = ImmutableField.immutableSetOf(staticFields);
@@ -115,13 +118,13 @@
     public ImmutableClassDef(@Nonnull String type,
                              int accessFlags,
                              @Nullable String superclass,
-                             @Nullable ImmutableList<String> interfaces,
+                             @Nullable List<String> interfaces,
                              @Nullable String sourceFile,
-                             @Nullable ImmutableSet<? extends ImmutableAnnotation> annotations,
-                             @Nullable ImmutableSortedSet<? extends ImmutableField> staticFields,
-                             @Nullable ImmutableSortedSet<? extends ImmutableField> instanceFields,
-                             @Nullable ImmutableSortedSet<? extends ImmutableMethod> directMethods,
-                             @Nullable ImmutableSortedSet<? extends ImmutableMethod> virtualMethods) {
+                             @Nullable Set<? extends ImmutableAnnotation> annotations,
+                             @Nullable SortedSet<? extends ImmutableField> staticFields,
+                             @Nullable SortedSet<? extends ImmutableField> instanceFields,
+                             @Nullable SortedSet<? extends ImmutableMethod> directMethods,
+                             @Nullable SortedSet<? extends ImmutableMethod> virtualMethods) {
         this.type = type;
         this.accessFlags = accessFlags;
         this.superclass = superclass;
@@ -154,48 +157,28 @@
     @Nonnull @Override public String getType() { return type; }
     @Override public int getAccessFlags() { return accessFlags; }
     @Nullable @Override public String getSuperclass() { return superclass; }
-    @Nonnull @Override public ImmutableList<String> getInterfaces() { return interfaces; }
+    @Nonnull @Override public List<String> getInterfaces() { return interfaces; }
     @Nullable @Override public String getSourceFile() { return sourceFile; }
-    @Nonnull @Override public ImmutableSet<? extends ImmutableAnnotation> getAnnotations() { return annotations; }
-    @Nonnull @Override public ImmutableSet<? extends ImmutableField> getStaticFields() { return staticFields; }
-    @Nonnull @Override public ImmutableSet<? extends ImmutableField> getInstanceFields() { return instanceFields; }
-    @Nonnull @Override public ImmutableSet<? extends ImmutableMethod> getDirectMethods() { return directMethods; }
-    @Nonnull @Override public ImmutableSet<? extends ImmutableMethod> getVirtualMethods() { return virtualMethods; }
+    @Nonnull @Override public Set<? extends ImmutableAnnotation> getAnnotations() { return annotations; }
+    @Nonnull @Override public Set<? extends ImmutableField> getStaticFields() { return staticFields; }
+    @Nonnull @Override public Set<? extends ImmutableField> getInstanceFields() { return instanceFields; }
+    @Nonnull @Override public Set<? extends ImmutableMethod> getDirectMethods() { return directMethods; }
+    @Nonnull @Override public Set<? extends ImmutableMethod> getVirtualMethods() { return virtualMethods; }
 
     @Nonnull
     @Override
-    public Collection<? extends ImmutableField> getFields() {
-        return new AbstractCollection<ImmutableField>() {
-            @Nonnull
-            @Override
-            public Iterator<ImmutableField> iterator() {
-                return Iterators.concat(staticFields.iterator(), instanceFields.iterator());
-            }
-
-            @Override public int size() {
-                return staticFields.size() + instanceFields.size();
-            }
-        };
+    public Iterable<? extends ImmutableField> getFields() {
+        return new ChainedIterator(staticFields, instanceFields);
     }
 
     @Nonnull
     @Override
-    public Collection<? extends ImmutableMethod> getMethods() {
-        return new AbstractCollection<ImmutableMethod>() {
-            @Nonnull
-            @Override
-            public Iterator<ImmutableMethod> iterator() {
-                return Iterators.concat(directMethods.iterator(), virtualMethods.iterator());
-            }
-
-            @Override public int size() {
-                return directMethods.size() + virtualMethods.size();
-            }
-        };
+    public Iterable<? extends ImmutableMethod> getMethods() {
+        return new ChainedIterator(directMethods, virtualMethods);
     }
 
     @Nonnull
-    public static ImmutableSet<ImmutableClassDef> immutableSetOf(@Nullable Iterable<? extends ClassDef> iterable) {
+    public static Set<ImmutableClassDef> immutableSetOf(@Nullable Iterable<? extends ClassDef> iterable) {
         return CONVERTER.toSet(iterable);
     }
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableDexFile.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableDexFile.java
index 5c9a40c..d27fdec 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableDexFile.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableDexFile.java
@@ -34,14 +34,14 @@
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.iface.DexFile;
 import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableSet;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Collection;
+import java.util.Set;
 
 public class ImmutableDexFile implements DexFile {
-    @Nonnull protected final ImmutableSet<? extends ImmutableClassDef> classes;
+    @Nonnull protected final Set<? extends ImmutableClassDef> classes;
     @Nonnull private final Opcodes opcodes;
 
     public ImmutableDexFile(@Nonnull Opcodes opcodes, @Nullable Collection<? extends ClassDef> classes) {
@@ -49,7 +49,7 @@
         this.opcodes = opcodes;
     }
 
-    public ImmutableDexFile(@Nonnull Opcodes opcodes, @Nullable ImmutableSet<? extends ImmutableClassDef> classes) {
+    public ImmutableDexFile(@Nonnull Opcodes opcodes, @Nullable Set<? extends ImmutableClassDef> classes) {
         this.classes = ImmutableUtils.nullToEmptySet(classes);
         this.opcodes = opcodes;
     }
@@ -61,6 +61,6 @@
         return new ImmutableDexFile(dexFile.getOpcodes(), dexFile.getClasses());
     }
 
-    @Nonnull @Override public ImmutableSet<? extends ImmutableClassDef> getClasses() { return classes; }
+    @Nonnull @Override public Set<? extends ImmutableClassDef> getClasses() { return classes; }
     @Nonnull @Override public Opcodes getOpcodes() { return opcodes; }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableExceptionHandler.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableExceptionHandler.java
index e8cd7fa..ab8f08c 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableExceptionHandler.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableExceptionHandler.java
@@ -33,10 +33,10 @@
 import com.android.tools.smali.dexlib2.base.BaseExceptionHandler;
 import com.android.tools.smali.dexlib2.iface.ExceptionHandler;
 import com.android.tools.smali.util.ImmutableConverter;
-import com.google.common.collect.ImmutableList;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.List;
 
 public class ImmutableExceptionHandler extends BaseExceptionHandler implements ExceptionHandler {
     @Nullable protected final String exceptionType;
@@ -61,7 +61,7 @@
     @Override public int getHandlerCodeAddress() { return handlerCodeAddress; }
 
     @Nonnull
-    public static ImmutableList<ImmutableExceptionHandler> immutableListOf(
+    public static List<ImmutableExceptionHandler> immutableListOf(
             @Nullable Iterable<? extends ExceptionHandler> list) {
         return CONVERTER.toList(list);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableField.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableField.java
index d5cb7fc..3e32aff 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableField.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableField.java
@@ -30,6 +30,8 @@
 
 package com.android.tools.smali.dexlib2.immutable;
 
+import static java.util.Collections.unmodifiableSet;
+
 import com.android.tools.smali.dexlib2.HiddenApiRestriction;
 import com.android.tools.smali.dexlib2.base.reference.BaseFieldReference;
 import com.android.tools.smali.dexlib2.iface.Annotation;
@@ -37,16 +39,16 @@
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 import com.android.tools.smali.dexlib2.immutable.value.ImmutableEncodedValue;
 import com.android.tools.smali.dexlib2.immutable.value.ImmutableEncodedValueFactory;
+import com.android.tools.smali.util.CollectionUtils;
 import com.android.tools.smali.util.ImmutableConverter;
-import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.collect.Ordering;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Collection;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Set;
+import java.util.SortedSet;
 
 public class ImmutableField extends BaseFieldReference implements Field {
     @Nonnull protected final String definingClass;
@@ -54,8 +56,8 @@
     @Nonnull protected final String type;
     protected final int accessFlags;
     @Nullable protected final ImmutableEncodedValue initialValue;
-    @Nonnull protected final ImmutableSet<? extends ImmutableAnnotation> annotations;
-    @Nonnull protected final ImmutableSet<HiddenApiRestriction> hiddenApiRestrictions;
+    @Nonnull protected final Set<? extends ImmutableAnnotation> annotations;
+    @Nonnull protected final Set<HiddenApiRestriction> hiddenApiRestrictions;
 
     public ImmutableField(@Nonnull String definingClass,
                           @Nonnull String name,
@@ -70,24 +72,8 @@
         this.accessFlags = accessFlags;
         this.initialValue = ImmutableEncodedValueFactory.ofNullable(initialValue);
         this.annotations = ImmutableAnnotation.immutableSetOf(annotations);
-        this.hiddenApiRestrictions =
-                hiddenApiRestrictions == null ? ImmutableSet.of() : ImmutableSet.copyOf(hiddenApiRestrictions);
-    }
-
-    public ImmutableField(@Nonnull String definingClass,
-                          @Nonnull String name,
-                          @Nonnull String type,
-                          int accessFlags,
-                          @Nullable ImmutableEncodedValue initialValue,
-                          @Nullable ImmutableSet<? extends ImmutableAnnotation> annotations,
-                          @Nullable ImmutableSet<HiddenApiRestriction> hiddenApiRestrictions) {
-        this.definingClass = definingClass;
-        this.name = name;
-        this.type = type;
-        this.accessFlags = accessFlags;
-        this.initialValue = initialValue;
-        this.annotations = ImmutableUtils.nullToEmptySet(annotations);
-        this.hiddenApiRestrictions = ImmutableUtils.nullToEmptySet(hiddenApiRestrictions);
+        this.hiddenApiRestrictions = hiddenApiRestrictions == null ? Collections.emptySet()
+                : unmodifiableSet(new HashSet<>(hiddenApiRestrictions));
     }
 
     public static ImmutableField of(Field field) {
@@ -109,12 +95,12 @@
     @Nonnull @Override public String getType() { return type; }
     @Override public int getAccessFlags() { return accessFlags; }
     @Override public EncodedValue getInitialValue() { return initialValue;}
-    @Nonnull @Override public ImmutableSet<? extends ImmutableAnnotation> getAnnotations() { return annotations; }
+    @Nonnull @Override public Set<? extends ImmutableAnnotation> getAnnotations() { return annotations; }
     @Nonnull @Override public Set<HiddenApiRestriction> getHiddenApiRestrictions() { return hiddenApiRestrictions; }
 
     @Nonnull
-    public static ImmutableSortedSet<ImmutableField> immutableSetOf(@Nullable Iterable<? extends Field> list) {
-        return CONVERTER.toSortedSet(Ordering.natural(), list);
+    public static SortedSet<ImmutableField> immutableSetOf(@Nullable Iterable<? extends Field> list) {
+        return CONVERTER.toSortedSet(CollectionUtils.naturalOrdering(), list);
     }
 
     private static final ImmutableConverter<ImmutableField, Field> CONVERTER =
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMethod.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMethod.java
index 09aa81b..e38da3a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMethod.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMethod.java
@@ -30,31 +30,34 @@
 
 package com.android.tools.smali.dexlib2.immutable;
 
+import static java.util.Collections.unmodifiableSet;
+
 import com.android.tools.smali.dexlib2.HiddenApiRestriction;
 import com.android.tools.smali.dexlib2.base.reference.BaseMethodReference;
 import com.android.tools.smali.dexlib2.iface.Annotation;
 import com.android.tools.smali.dexlib2.iface.Method;
 import com.android.tools.smali.dexlib2.iface.MethodImplementation;
 import com.android.tools.smali.dexlib2.iface.MethodParameter;
+import com.android.tools.smali.util.CollectionUtils;
 import com.android.tools.smali.util.ImmutableConverter;
 import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.collect.Ordering;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
+import java.util.SortedSet;
 
 public class ImmutableMethod extends BaseMethodReference implements Method {
     @Nonnull protected final String definingClass;
     @Nonnull protected final String name;
-    @Nonnull protected final ImmutableList<? extends ImmutableMethodParameter> parameters;
+    @Nonnull protected final List<? extends ImmutableMethodParameter> parameters;
     @Nonnull protected final String returnType;
     protected final int accessFlags;
-    @Nonnull protected final ImmutableSet<? extends ImmutableAnnotation> annotations;
-    @Nonnull protected final ImmutableSet<HiddenApiRestriction> hiddenApiRestrictions;
+    @Nonnull protected final Set<? extends ImmutableAnnotation> annotations;
+    @Nonnull protected final Set<HiddenApiRestriction> hiddenApiRestrictions;
     @Nullable protected final ImmutableMethodImplementation methodImplementation;
 
     public ImmutableMethod(@Nonnull String definingClass,
@@ -72,17 +75,18 @@
         this.accessFlags = accessFlags;
         this.annotations = ImmutableAnnotation.immutableSetOf(annotations);
         this.hiddenApiRestrictions =
-                hiddenApiRestrictions == null ? ImmutableSet.of() : ImmutableSet.copyOf(hiddenApiRestrictions);
+                hiddenApiRestrictions == null ? Collections.emptySet() : 
+                        unmodifiableSet(new HashSet<>(hiddenApiRestrictions));
         this.methodImplementation = ImmutableMethodImplementation.of(methodImplementation);
     }
 
     public ImmutableMethod(@Nonnull String definingClass,
                            @Nonnull String name,
-                           @Nullable ImmutableList<? extends ImmutableMethodParameter> parameters,
+                           @Nullable List<? extends ImmutableMethodParameter> parameters,
                            @Nonnull String returnType,
                            int accessFlags,
-                           @Nullable ImmutableSet<? extends ImmutableAnnotation> annotations,
-                           @Nullable ImmutableSet<HiddenApiRestriction> hiddenApiRestrictions,
+                           @Nullable Set<? extends ImmutableAnnotation> annotations,
+                           @Nullable Set<HiddenApiRestriction> hiddenApiRestrictions,
                            @Nullable ImmutableMethodImplementation methodImplementation) {
         this.definingClass = definingClass;
         this.name = name;
@@ -111,17 +115,17 @@
 
     @Override @Nonnull public String getDefiningClass() { return definingClass; }
     @Override @Nonnull public String getName() { return name; }
-    @Override @Nonnull public ImmutableList<? extends CharSequence> getParameterTypes() { return parameters; }
-    @Override @Nonnull public ImmutableList<? extends ImmutableMethodParameter> getParameters() { return parameters; }
+    @Override @Nonnull public List<? extends CharSequence> getParameterTypes() { return parameters; }
+    @Override @Nonnull public List<? extends ImmutableMethodParameter> getParameters() { return parameters; }
     @Override @Nonnull public String getReturnType() { return returnType; }
     @Override public int getAccessFlags() { return accessFlags; }
-    @Override @Nonnull public ImmutableSet<? extends ImmutableAnnotation> getAnnotations() { return annotations; }
+    @Override @Nonnull public Set<? extends ImmutableAnnotation> getAnnotations() { return annotations; }
     @Nonnull @Override public Set<HiddenApiRestriction> getHiddenApiRestrictions() { return hiddenApiRestrictions; }
     @Override @Nullable public ImmutableMethodImplementation getImplementation() { return methodImplementation; }
 
     @Nonnull
-    public static ImmutableSortedSet<ImmutableMethod> immutableSetOf(@Nullable Iterable<? extends Method> list) {
-        return CONVERTER.toSortedSet(Ordering.natural(), list);
+    public static SortedSet<ImmutableMethod> immutableSetOf(@Nullable Iterable<? extends Method> list) {
+        return CONVERTER.toSortedSet(CollectionUtils.naturalOrdering(), list);
     }
 
     private static final ImmutableConverter<ImmutableMethod, Method> CONVERTER =
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMethodImplementation.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMethodImplementation.java
index 10bc833..2fdeba9 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMethodImplementation.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMethodImplementation.java
@@ -38,7 +38,6 @@
 import com.android.tools.smali.dexlib2.immutable.debug.ImmutableDebugItem;
 import com.android.tools.smali.dexlib2.immutable.instruction.ImmutableInstruction;
 import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableList;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -46,9 +45,9 @@
 
 public class ImmutableMethodImplementation implements MethodImplementation {
     protected final int registerCount;
-    @Nonnull protected final ImmutableList<? extends ImmutableInstruction> instructions;
-    @Nonnull protected final ImmutableList<? extends ImmutableTryBlock> tryBlocks;
-    @Nonnull protected final ImmutableList<? extends ImmutableDebugItem> debugItems;
+    @Nonnull protected final List<? extends ImmutableInstruction> instructions;
+    @Nonnull protected final List<? extends ImmutableTryBlock> tryBlocks;
+    @Nonnull protected final List<? extends ImmutableDebugItem> debugItems;
 
     public ImmutableMethodImplementation(int registerCount,
                                          @Nullable Iterable<? extends Instruction> instructions,
@@ -61,9 +60,9 @@
     }
 
     public ImmutableMethodImplementation(int registerCount,
-                                         @Nullable ImmutableList<? extends ImmutableInstruction> instructions,
-                                         @Nullable ImmutableList<? extends ImmutableTryBlock> tryBlocks,
-                                         @Nullable ImmutableList<? extends ImmutableDebugItem> debugItems) {
+                                         @Nullable List<? extends ImmutableInstruction> instructions,
+                                         @Nullable List<? extends ImmutableTryBlock> tryBlocks,
+                                         @Nullable List<? extends ImmutableDebugItem> debugItems) {
         this.registerCount = registerCount;
         this.instructions = ImmutableUtils.nullToEmptyList(instructions);
         this.tryBlocks = ImmutableUtils.nullToEmptyList(tryBlocks);
@@ -86,7 +85,7 @@
     }
 
     @Override public int getRegisterCount() { return registerCount; }
-    @Nonnull @Override public ImmutableList<? extends ImmutableInstruction> getInstructions() { return instructions; }
-    @Nonnull @Override public ImmutableList<? extends ImmutableTryBlock> getTryBlocks() { return tryBlocks; }
-    @Nonnull @Override public ImmutableList<? extends ImmutableDebugItem> getDebugItems() { return debugItems; }
+    @Nonnull @Override public List<? extends ImmutableInstruction> getInstructions() { return instructions; }
+    @Nonnull @Override public List<? extends ImmutableTryBlock> getTryBlocks() { return tryBlocks; }
+    @Nonnull @Override public List<? extends ImmutableDebugItem> getDebugItems() { return debugItems; }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMethodParameter.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMethodParameter.java
index 37d815d..8dc0a41 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMethodParameter.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMethodParameter.java
@@ -34,17 +34,15 @@
 import com.android.tools.smali.dexlib2.iface.Annotation;
 import com.android.tools.smali.dexlib2.iface.MethodParameter;
 import com.android.tools.smali.util.ImmutableConverter;
-import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.List;
 import java.util.Set;
 
 public class ImmutableMethodParameter extends BaseMethodParameter {
     @Nonnull protected final String type;
-    @Nonnull protected final ImmutableSet<? extends ImmutableAnnotation> annotations;
+    @Nonnull protected final Set<? extends ImmutableAnnotation> annotations;
     @Nullable protected final String name;
 
     public ImmutableMethodParameter(@Nonnull String type,
@@ -55,14 +53,6 @@
         this.name = name;
     }
 
-    public ImmutableMethodParameter(@Nonnull String type,
-                                    @Nullable ImmutableSet<? extends ImmutableAnnotation> annotations,
-                                    @Nullable String name) {
-        this.type = type;
-        this.annotations = ImmutableUtils.nullToEmptySet(annotations);
-        this.name = name;
-    }
-
     public static ImmutableMethodParameter of(MethodParameter methodParameter) {
         if (methodParameter instanceof ImmutableMethodParameter) {
             return (ImmutableMethodParameter)methodParameter;
@@ -81,7 +71,7 @@
     @Nullable @Override public String getSignature() { return null; }
 
     @Nonnull
-    public static ImmutableList<ImmutableMethodParameter> immutableListOf(
+    public static List<ImmutableMethodParameter> immutableListOf(
             @Nullable Iterable<? extends MethodParameter> list) {
         return CONVERTER.toList(list);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMultiDexContainer.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMultiDexContainer.java
index 2077bff..317ab45 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMultiDexContainer.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableMultiDexContainer.java
@@ -30,35 +30,37 @@
 
 package com.android.tools.smali.dexlib2.immutable;
 
+import static java.util.Collections.unmodifiableMap;
+import static java.util.Collections.unmodifiableList;
+
 import com.android.tools.smali.dexlib2.iface.MultiDexContainer;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.ArrayList;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
 public class ImmutableMultiDexContainer implements MultiDexContainer<ImmutableDexFile> {
 
-    private final ImmutableMap<String, ImmutableDexEntry> entries;
+    private final Map<String, ImmutableDexEntry> entries;
 
     public ImmutableMultiDexContainer(Map<String, ImmutableDexFile> entries) {
-        ImmutableMap.Builder<String, ImmutableDexEntry> builder = ImmutableMap.builder();
+        HashMap<String, ImmutableDexEntry> map = new HashMap<>();
 
         for (Map.Entry<String, ImmutableDexFile> entry : entries.entrySet()) {
             ImmutableDexEntry dexEntry = new ImmutableDexEntry(entry.getKey(), entry.getValue());
-            builder.put(dexEntry.getEntryName(), dexEntry);
+            map.put(dexEntry.getEntryName(), dexEntry);
         }
 
-        this.entries = builder.build();
+        this.entries = unmodifiableMap(map);
     }
 
-
     @Nonnull
     @Override
     public List<String> getDexEntryNames() {
-        return ImmutableList.copyOf(entries.keySet());
+        return unmodifiableList(new ArrayList<>(entries.keySet()));
     }
 
     @Nullable
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableTryBlock.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableTryBlock.java
index 9b7ca4a..cc60b81 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableTryBlock.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/ImmutableTryBlock.java
@@ -34,8 +34,6 @@
 import com.android.tools.smali.dexlib2.iface.ExceptionHandler;
 import com.android.tools.smali.dexlib2.iface.TryBlock;
 import com.android.tools.smali.util.ImmutableConverter;
-import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableList;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -44,7 +42,7 @@
 public class ImmutableTryBlock extends BaseTryBlock<ImmutableExceptionHandler> {
     protected final int startCodeAddress;
     protected final int codeUnitCount;
-    @Nonnull protected final ImmutableList<? extends ImmutableExceptionHandler> exceptionHandlers;
+    @Nonnull protected final List<? extends ImmutableExceptionHandler> exceptionHandlers;
 
     public ImmutableTryBlock(int startCodeAddress,
                              int codeUnitCount,
@@ -54,14 +52,6 @@
         this.exceptionHandlers = ImmutableExceptionHandler.immutableListOf(exceptionHandlers);
     }
 
-    public ImmutableTryBlock(int startCodeAddress,
-                             int codeUnitCount,
-                             @Nullable ImmutableList<? extends ImmutableExceptionHandler> exceptionHandlers) {
-        this.startCodeAddress = startCodeAddress;
-        this.codeUnitCount = codeUnitCount;
-        this.exceptionHandlers = ImmutableUtils.nullToEmptyList(exceptionHandlers);
-    }
-
     public static ImmutableTryBlock of(TryBlock<? extends ExceptionHandler> tryBlock) {
         if (tryBlock instanceof ImmutableTryBlock) {
             return (ImmutableTryBlock)tryBlock;
@@ -75,12 +65,12 @@
     @Override public int getStartCodeAddress() { return startCodeAddress; }
     @Override public int getCodeUnitCount() { return codeUnitCount; }
 
-    @Nonnull @Override public ImmutableList<? extends ImmutableExceptionHandler> getExceptionHandlers() {
+    @Nonnull @Override public List<? extends ImmutableExceptionHandler> getExceptionHandlers() {
         return exceptionHandlers;
     }
 
     @Nonnull
-    public static ImmutableList<ImmutableTryBlock> immutableListOf(
+    public static List<ImmutableTryBlock> immutableListOf(
             @Nullable List<? extends TryBlock<? extends ExceptionHandler>> list) {
         return CONVERTER.toList(list);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/README.md b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/README.md
new file mode 100644
index 0000000..892ac51
--- /dev/null
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/README.md
@@ -0,0 +1,4 @@
+## About
+This folder contains classes that originally relied on Guava based Immutable collections, thus the
+naming. The current implementations rely on the Java unmodifiable collections or on constructor
+helpers that produce immutable collections from Java Collections.
\ No newline at end of file
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/debug/ImmutableDebugItem.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/debug/ImmutableDebugItem.java
index 6e7c706..b119b14 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/debug/ImmutableDebugItem.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/debug/ImmutableDebugItem.java
@@ -41,10 +41,10 @@
 import com.android.tools.smali.dexlib2.iface.debug.StartLocal;
 import com.android.tools.smali.util.ExceptionWithContext;
 import com.android.tools.smali.util.ImmutableConverter;
-import com.google.common.collect.ImmutableList;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.List;
 
 public abstract class ImmutableDebugItem implements DebugItem {
     protected final int codeAddress;
@@ -81,7 +81,7 @@
     @Override public int getCodeAddress() { return codeAddress; }
 
     @Nonnull
-    public static ImmutableList<ImmutableDebugItem> immutableListOf(@Nullable Iterable<? extends DebugItem> list) {
+    public static List<ImmutableDebugItem> immutableListOf(@Nullable Iterable<? extends DebugItem> list) {
         return CONVERTER.toList(list);
     }
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableArrayPayload.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableArrayPayload.java
index c359a6c..4f815b2 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableArrayPayload.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableArrayPayload.java
@@ -30,36 +30,33 @@
 
 package com.android.tools.smali.dexlib2.immutable.instruction;
 
+import static java.util.Collections.unmodifiableList;
+
 import com.android.tools.smali.dexlib2.Format;
 import com.android.tools.smali.dexlib2.Opcode;
 import com.android.tools.smali.dexlib2.util.Preconditions;
-import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableList;
+
 import com.android.tools.smali.dexlib2.iface.instruction.formats.ArrayPayload;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
+
 public class ImmutableArrayPayload extends ImmutableInstruction implements ArrayPayload {
     public static final Opcode OPCODE = Opcode.ARRAY_PAYLOAD;
 
     protected final int elementWidth;
-    @Nonnull protected final ImmutableList<Number> arrayElements;
+    @Nonnull protected final List<Number> arrayElements;
 
-    public ImmutableArrayPayload(int elementWidth,
-                                 @Nullable List<Number> arrayElements) {
+    public ImmutableArrayPayload(int elementWidth, @Nullable List<Number> arrayElements) {
         super(OPCODE);
         this.elementWidth = Preconditions.checkArrayPayloadElementWidth(elementWidth);
         this.arrayElements = Preconditions.checkArrayPayloadElements(elementWidth,
-                arrayElements==null ? ImmutableList.<Number>of() : ImmutableList.copyOf(arrayElements));
-    }
-
-    public ImmutableArrayPayload(int elementWidth,
-                                 @Nullable ImmutableList<Number> arrayElements) {
-        super(OPCODE);
-        this.elementWidth = Preconditions.checkArrayPayloadElementWidth(elementWidth);
-        this.arrayElements = Preconditions.checkArrayPayloadElements(elementWidth, ImmutableUtils.nullToEmptyList(arrayElements));
+                arrayElements == null ? Collections.emptyList()
+                    : unmodifiableList(new ArrayList<>(arrayElements)));
     }
 
     @Nonnull
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableInstruction.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableInstruction.java
index fda86fa..f70dcee 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableInstruction.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableInstruction.java
@@ -71,10 +71,10 @@
 import com.android.tools.smali.dexlib2.iface.instruction.formats.UnknownInstruction;
 import com.android.tools.smali.dexlib2.util.Preconditions;
 import com.android.tools.smali.util.ImmutableConverter;
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.iface.instruction.Instruction;
 
 import javax.annotation.Nonnull;
+import java.util.List;
 
 public abstract class ImmutableInstruction implements Instruction {
     @Nonnull protected final Opcode opcode;
@@ -182,7 +182,7 @@
     }
 
     @Nonnull
-    public static ImmutableList<ImmutableInstruction> immutableListOf(Iterable<? extends Instruction> list) {
+    public static List<ImmutableInstruction> immutableListOf(Iterable<? extends Instruction> list) {
         return CONVERTER.toList(list);
     }
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutablePackedSwitchPayload.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutablePackedSwitchPayload.java
index 5ed73e0..6d68f4b 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutablePackedSwitchPayload.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutablePackedSwitchPayload.java
@@ -34,8 +34,6 @@
 import com.android.tools.smali.dexlib2.Opcode;
 import com.android.tools.smali.dexlib2.iface.instruction.formats.PackedSwitchPayload;
 import com.android.tools.smali.dexlib2.util.Preconditions;
-import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.iface.instruction.SwitchElement;
 
 import javax.annotation.Nonnull;
@@ -46,19 +44,13 @@
     PackedSwitchPayload {
     public static final Opcode OPCODE = Opcode.PACKED_SWITCH_PAYLOAD;
 
-    @Nonnull protected final ImmutableList<? extends ImmutableSwitchElement> switchElements;
+    @Nonnull protected final List<? extends ImmutableSwitchElement> switchElements;
 
     public ImmutablePackedSwitchPayload(@Nullable List<? extends SwitchElement> switchElements) {
         super(OPCODE);
         this.switchElements = Preconditions.checkSequentialOrderedKeys(ImmutableSwitchElement.immutableListOf(switchElements));
     }
 
-    public ImmutablePackedSwitchPayload(
-            @Nullable ImmutableList<? extends ImmutableSwitchElement> switchElements) {
-        super(OPCODE);
-        this.switchElements = Preconditions.checkSequentialOrderedKeys(ImmutableUtils.nullToEmptyList(switchElements));
-    }
-
     @Nonnull
     public static ImmutablePackedSwitchPayload of(PackedSwitchPayload instruction) {
         if (instruction instanceof ImmutablePackedSwitchPayload) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableSparseSwitchPayload.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableSparseSwitchPayload.java
index 43e76ac..d563f6d 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableSparseSwitchPayload.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableSparseSwitchPayload.java
@@ -33,8 +33,6 @@
 import com.android.tools.smali.dexlib2.Format;
 import com.android.tools.smali.dexlib2.Opcode;
 import com.android.tools.smali.dexlib2.iface.instruction.formats.SparseSwitchPayload;
-import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.iface.instruction.SwitchElement;
 
 import javax.annotation.Nonnull;
@@ -45,19 +43,13 @@
     SparseSwitchPayload {
     public static final Opcode OPCODE = Opcode.SPARSE_SWITCH_PAYLOAD;
 
-    @Nonnull protected final ImmutableList<? extends ImmutableSwitchElement> switchElements;
+    @Nonnull protected final List<? extends ImmutableSwitchElement> switchElements;
 
     public ImmutableSparseSwitchPayload(@Nullable List<? extends SwitchElement> switchElements) {
         super(OPCODE);
         this.switchElements = ImmutableSwitchElement.immutableListOf(switchElements);
     }
 
-    public ImmutableSparseSwitchPayload(
-            @Nullable ImmutableList<? extends ImmutableSwitchElement> switchElements) {
-        super(OPCODE);
-        this.switchElements = ImmutableUtils.nullToEmptyList(switchElements);
-    }
-
     @Nonnull
     public static ImmutableSparseSwitchPayload of(SparseSwitchPayload instruction) {
         if (instruction instanceof ImmutableSparseSwitchPayload) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableSwitchElement.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableSwitchElement.java
index 79e1027..e5a2be4 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableSwitchElement.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/instruction/ImmutableSwitchElement.java
@@ -31,7 +31,6 @@
 package com.android.tools.smali.dexlib2.immutable.instruction;
 
 import com.android.tools.smali.util.ImmutableConverter;
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.iface.instruction.SwitchElement;
 
 import javax.annotation.Nonnull;
@@ -62,7 +61,7 @@
     @Override public int getOffset() { return offset; }
 
     @Nonnull
-    public static ImmutableList<ImmutableSwitchElement> immutableListOf(@Nullable List<? extends SwitchElement> list) {
+    public static List<ImmutableSwitchElement> immutableListOf(@Nullable List<? extends SwitchElement> list) {
         return CONVERTER.toList(list);
     }
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableCallSiteReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableCallSiteReference.java
index 62d969b..67bcf03 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableCallSiteReference.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableCallSiteReference.java
@@ -31,7 +31,6 @@
 package com.android.tools.smali.dexlib2.immutable.reference;
 
 import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.base.reference.BaseCallSiteReference;
 import com.android.tools.smali.dexlib2.iface.reference.CallSiteReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodHandleReference;
@@ -49,7 +48,7 @@
     @Nonnull protected final ImmutableMethodHandleReference methodHandle;
     @Nonnull protected final String methodName;
     @Nonnull protected final ImmutableMethodProtoReference methodProto;
-    @Nonnull protected final ImmutableList<? extends ImmutableEncodedValue> extraArguments;
+    @Nonnull protected final List<? extends ImmutableEncodedValue> extraArguments;
 
     public ImmutableCallSiteReference(@Nonnull String name, @Nonnull MethodHandleReference methodHandle,
                                       @Nonnull String methodName, @Nonnull MethodProtoReference methodProto,
@@ -63,7 +62,7 @@
 
     public ImmutableCallSiteReference(@Nonnull String name, @Nonnull ImmutableMethodHandleReference methodHandle,
                                       @Nonnull String methodName, @Nonnull ImmutableMethodProtoReference methodProto,
-                                      @Nullable ImmutableList<? extends ImmutableEncodedValue> extraArguments) {
+                                      @Nullable List<? extends ImmutableEncodedValue> extraArguments) {
         this.name = name;
         this.methodHandle = methodHandle;
         this.methodName = methodName;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableMethodProtoReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableMethodProtoReference.java
index 5fe4f0f..bec5c37 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableMethodProtoReference.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableMethodProtoReference.java
@@ -31,7 +31,6 @@
 package com.android.tools.smali.dexlib2.immutable.reference;
 
 import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.base.reference.BaseMethodProtoReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodProtoReference;
 import com.android.tools.smali.dexlib2.immutable.util.CharSequenceConverter;
@@ -41,10 +40,10 @@
 import java.util.List;
 
 public class ImmutableMethodProtoReference extends BaseMethodProtoReference implements ImmutableReference {
-    @Nonnull protected final ImmutableList<String> parameters;
+    @Nonnull protected final List<String> parameters;
     @Nonnull protected final String returnType;
 
-    public ImmutableMethodProtoReference(@Nullable ImmutableList<String> parameters,
+    public ImmutableMethodProtoReference(@Nullable List<String> parameters,
                                          @Nonnull String returnType) {
         this.parameters = ImmutableUtils.nullToEmptyList(parameters);
         this.returnType = returnType;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableMethodReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableMethodReference.java
index 842d838..b81337d 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableMethodReference.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableMethodReference.java
@@ -31,18 +31,18 @@
 package com.android.tools.smali.dexlib2.immutable.reference;
 
 import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.base.reference.BaseMethodReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
 import com.android.tools.smali.dexlib2.immutable.util.CharSequenceConverter;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.List;
 
 public class ImmutableMethodReference extends BaseMethodReference implements ImmutableReference {
     @Nonnull protected final String definingClass;
     @Nonnull protected final String name;
-    @Nonnull protected final ImmutableList<String> parameters;
+    @Nonnull protected final List<String> parameters;
     @Nonnull protected final String returnType;
 
     public ImmutableMethodReference(@Nonnull String definingClass,
@@ -57,7 +57,7 @@
 
     public ImmutableMethodReference(@Nonnull String definingClass,
                                     @Nonnull String name,
-                                    @Nullable ImmutableList<String> parameters,
+                                    @Nullable List<String> parameters,
                                     @Nonnull String returnType) {
         this.definingClass = definingClass;
         this.name = name;
@@ -79,7 +79,7 @@
 
     @Nonnull @Override public String getDefiningClass() { return definingClass; }
     @Nonnull @Override public String getName() { return name; }
-    @Nonnull @Override public ImmutableList<String> getParameterTypes() { return parameters; }
+    @Nonnull @Override public List<String> getParameterTypes() { return parameters; }
     @Nonnull @Override public String getReturnType() { return returnType; }
 
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableTypeReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableTypeReference.java
index 5560bc1..f2980f5 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableTypeReference.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/reference/ImmutableTypeReference.java
@@ -31,7 +31,7 @@
 package com.android.tools.smali.dexlib2.immutable.reference;
 
 import com.android.tools.smali.util.ImmutableConverter;
-import com.google.common.collect.ImmutableList;
+
 import com.android.tools.smali.dexlib2.base.reference.BaseTypeReference;
 import com.android.tools.smali.dexlib2.iface.reference.TypeReference;
 
@@ -57,7 +57,7 @@
     @Nonnull @Override public String getType() { return type; }
 
     @Nonnull
-    public static ImmutableList<ImmutableTypeReference> immutableListOf(@Nullable List<? extends TypeReference> list) {
+    public static List<ImmutableTypeReference> immutableListOf(@Nullable List<? extends TypeReference> list) {
         return CONVERTER.toList(list);
     }
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/util/CharSequenceConverter.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/util/CharSequenceConverter.java
index 09020d0..4f2a27a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/util/CharSequenceConverter.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/util/CharSequenceConverter.java
@@ -31,17 +31,17 @@
 package com.android.tools.smali.dexlib2.immutable.util;
 
 import com.android.tools.smali.util.ImmutableConverter;
-import com.google.common.collect.ImmutableList;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.List;
 
 public final class CharSequenceConverter {
     private CharSequenceConverter() {
     }
 
     @Nonnull
-    public static ImmutableList<String> immutableStringList(@Nullable Iterable<? extends CharSequence> iterable) {
+    public static List<String> immutableStringList(@Nullable Iterable<? extends CharSequence> iterable) {
         return CONVERTER.toList(iterable);
     }
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/value/ImmutableAnnotationEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/value/ImmutableAnnotationEncodedValue.java
index b42e73d..10e83cb 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/value/ImmutableAnnotationEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/value/ImmutableAnnotationEncodedValue.java
@@ -32,7 +32,6 @@
 
 import com.android.tools.smali.dexlib2.iface.AnnotationElement;
 import com.android.tools.smali.util.ImmutableUtils;
-import com.google.common.collect.ImmutableSet;
 import com.android.tools.smali.dexlib2.base.value.BaseAnnotationEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.AnnotationEncodedValue;
 import com.android.tools.smali.dexlib2.immutable.ImmutableAnnotationElement;
@@ -40,10 +39,11 @@
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Collection;
+import java.util.Set;
 
 public class ImmutableAnnotationEncodedValue extends BaseAnnotationEncodedValue implements ImmutableEncodedValue {
     @Nonnull protected final String type;
-    @Nonnull protected final ImmutableSet<? extends ImmutableAnnotationElement> elements;
+    @Nonnull protected final Set<? extends ImmutableAnnotationElement> elements;
 
     public ImmutableAnnotationEncodedValue(@Nonnull String type,
                                            @Nullable Collection<? extends AnnotationElement> elements) {
@@ -52,7 +52,7 @@
     }
 
     public ImmutableAnnotationEncodedValue(@Nonnull String type,
-                                           @Nullable ImmutableSet<? extends ImmutableAnnotationElement> elements) {
+                                           @Nullable Set<? extends ImmutableAnnotationElement> elements) {
         this.type = type;
         this.elements = ImmutableUtils.nullToEmptySet(elements);
     }
@@ -67,5 +67,5 @@
     }
 
     @Nonnull @Override public String getType() { return type; }
-    @Nonnull @Override public ImmutableSet<? extends ImmutableAnnotationElement> getElements() { return elements; }
+    @Nonnull @Override public Set<? extends ImmutableAnnotationElement> getElements() { return elements; }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/value/ImmutableArrayEncodedValue.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/value/ImmutableArrayEncodedValue.java
index d902593..cf27be1 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/value/ImmutableArrayEncodedValue.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/value/ImmutableArrayEncodedValue.java
@@ -30,22 +30,22 @@
 
 package com.android.tools.smali.dexlib2.immutable.value;
 
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.base.value.BaseArrayEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.ArrayEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 
 import javax.annotation.Nonnull;
 import java.util.Collection;
+import java.util.List;
 
 public class ImmutableArrayEncodedValue extends BaseArrayEncodedValue implements ImmutableEncodedValue {
-    @Nonnull protected final ImmutableList<? extends ImmutableEncodedValue> value;
+    @Nonnull protected final List<? extends ImmutableEncodedValue> value;
 
     public ImmutableArrayEncodedValue(@Nonnull Collection<? extends EncodedValue> value) {
         this.value = ImmutableEncodedValueFactory.immutableListOf(value);
     }
 
-    public ImmutableArrayEncodedValue(@Nonnull ImmutableList<ImmutableEncodedValue> value) {
+    public ImmutableArrayEncodedValue(@Nonnull List<ImmutableEncodedValue> value) {
         this.value = value;
     }
 
@@ -56,5 +56,5 @@
         return new ImmutableArrayEncodedValue(arrayEncodedValue.getValue());
     }
 
-    @Nonnull public ImmutableList<? extends ImmutableEncodedValue> getValue() { return value; }
+    @Nonnull public List<? extends ImmutableEncodedValue> getValue() { return value; }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/value/ImmutableEncodedValueFactory.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/value/ImmutableEncodedValueFactory.java
index e458a1e..1159b60 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/value/ImmutableEncodedValueFactory.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/immutable/value/ImmutableEncodedValueFactory.java
@@ -51,11 +51,10 @@
 import com.android.tools.smali.dexlib2.iface.value.TypeEncodedValue;
 import com.android.tools.smali.util.ExceptionWithContext;
 import com.android.tools.smali.util.ImmutableConverter;
-import com.google.common.base.Preconditions;
-import com.google.common.collect.ImmutableList;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.List;
 
 public class ImmutableEncodedValueFactory {
     @Nonnull
@@ -98,8 +97,7 @@
             case ValueType.METHOD_TYPE:
                 return ImmutableMethodTypeEncodedValue.of((MethodTypeEncodedValue) encodedValue);
             default:
-                Preconditions.checkArgument(false);
-                return null;
+                throw new IllegalArgumentException("Invalid value type.");
         }
     }
 
@@ -139,7 +137,7 @@
     }
 
     @Nonnull
-    public static ImmutableList<ImmutableEncodedValue> immutableListOf
+    public static List<ImmutableEncodedValue> immutableListOf
             (@Nullable Iterable<? extends EncodedValue> list) {
         return CONVERTER.toList(list);
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/CallSiteReferenceRewriter.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/CallSiteReferenceRewriter.java
index d19cebf..439ff76 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/CallSiteReferenceRewriter.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/CallSiteReferenceRewriter.java
@@ -30,8 +30,6 @@
 
 package com.android.tools.smali.dexlib2.rewriter;
 
-import com.google.common.base.Function;
-import com.google.common.collect.Lists;
 import com.android.tools.smali.dexlib2.base.reference.BaseCallSiteReference;
 import com.android.tools.smali.dexlib2.iface.reference.CallSiteReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodHandleReference;
@@ -40,6 +38,8 @@
 
 import javax.annotation.Nonnull;
 import java.util.List;
+import java.util.stream.Collectors;
+import java.util.function.Function;
 
 public class CallSiteReferenceRewriter implements Rewriter<CallSiteReference> {
     @Nonnull protected final Rewriters rewriters;
@@ -79,12 +79,11 @@
         }
 
         @Override @Nonnull public List<? extends EncodedValue> getExtraArguments() {
-            return Lists.transform(callSiteReference.getExtraArguments(),
-                    new Function<EncodedValue, EncodedValue>() {
-                        @Nonnull @Override public EncodedValue apply(EncodedValue encodedValue) {
-                            return RewriterUtils.rewriteValue(rewriters, encodedValue);
-                        }
-                    });
+            return callSiteReference.getExtraArguments().stream().map(new Function<EncodedValue, EncodedValue>() {
+                @Nonnull @Override public EncodedValue apply(EncodedValue encodedValue) {
+                    return RewriterUtils.rewriteValue(rewriters, encodedValue);
+                }
+            }).collect(Collectors.toList());
         }
     }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/ClassDefRewriter.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/ClassDefRewriter.java
index 6117d34..27d2c87 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/ClassDefRewriter.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/ClassDefRewriter.java
@@ -35,7 +35,7 @@
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.iface.Field;
 import com.android.tools.smali.dexlib2.iface.Method;
-import com.google.common.collect.Iterators;
+import com.android.tools.smali.util.ChainedIterator;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -100,7 +100,8 @@
                 @Nonnull
                 @Override
                 public Iterator<Field> iterator() {
-                    return Iterators.concat(getStaticFields().iterator(), getInstanceFields().iterator());
+                    return new ChainedIterator(
+                        getStaticFields().iterator(), getInstanceFields().iterator());
                 }
             };
         }
@@ -120,7 +121,8 @@
                 @Nonnull
                 @Override
                 public Iterator<Method> iterator() {
-                    return Iterators.concat(getDirectMethods().iterator(), getVirtualMethods().iterator());
+                    return new ChainedIterator(
+                        getDirectMethods().iterator(), getVirtualMethods().iterator());
                 }
             };
         }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/MethodReferenceRewriter.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/MethodReferenceRewriter.java
index c7b1d8c..b4209d8 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/MethodReferenceRewriter.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/MethodReferenceRewriter.java
@@ -32,11 +32,11 @@
 
 import com.android.tools.smali.dexlib2.base.reference.BaseMethodReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
-import com.google.common.base.Function;
-import com.google.common.collect.Lists;
 
 import javax.annotation.Nonnull;
 import java.util.List;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 public class MethodReferenceRewriter implements Rewriter<MethodReference> {
     @Nonnull protected final Rewriters rewriters;
@@ -66,12 +66,12 @@
 
         @Override @Nonnull public List<? extends CharSequence> getParameterTypes() {
             return RewriterUtils.rewriteList(rewriters.getTypeRewriter(),
-                    Lists.transform(methodReference.getParameterTypes(),
+                    methodReference.getParameterTypes().stream().map(
                     new Function<CharSequence, String>() {
                         @Nonnull @Override public String apply(CharSequence input) {
                             return input.toString();
                         }
-                    }));
+                    }).collect(Collectors.toList()));
         }
 
         @Override @Nonnull public String getReturnType() {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/RewriterUtils.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/RewriterUtils.java
index 652eb46..a9978b6 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/RewriterUtils.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/rewriter/RewriterUtils.java
@@ -53,14 +53,14 @@
 import com.android.tools.smali.dexlib2.iface.value.MethodHandleEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.MethodTypeEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.TypeEncodedValue;
-import com.google.common.base.Function;
-import com.google.common.collect.Lists;
 
 import java.util.AbstractList;
 import java.util.AbstractSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
@@ -183,12 +183,11 @@
         return new BaseMethodProtoReference() {
             @Nonnull @Override public List<? extends CharSequence> getParameterTypes() {
                 return rewriteList(typeRewriter,
-                        Lists.transform(methodProtoReference.getParameterTypes(),
+                        methodProtoReference.getParameterTypes().stream().map(
                         new Function<CharSequence, String>() {
                             @Nonnull @Override public String apply(CharSequence input) {
                                 return input.toString();
-                            }
-                        }));
+                            }}).collect(Collectors.toList()));
             }
 
             @Nonnull @Override public String getReturnType() {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/AnnotatedBytes.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/AnnotatedBytes.java
index 9b8e7f6..7fd0c4f 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/AnnotatedBytes.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/AnnotatedBytes.java
@@ -30,18 +30,16 @@
 
 package com.android.tools.smali.dexlib2.util;
 
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-
 import com.android.tools.smali.util.ExceptionWithContext;
 import com.android.tools.smali.util.Hex;
+import com.android.tools.smali.util.StringUtils;
 import com.android.tools.smali.util.TwoColumnOutput;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.io.IOException;
 import java.io.Writer;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 import java.util.TreeMap;
@@ -65,7 +63,7 @@
      * is the exclusive end point. The range annotation for a range is associated with the first key for that range.
      * The point annotations for a point are associated with the key at that point.
      */
-    @Nonnull private TreeMap<Integer, AnnotationEndpoint> annotatations = Maps.newTreeMap();
+    @Nonnull private TreeMap<Integer, AnnotationEndpoint> annotatations = new TreeMap<>();
 
     private int cursor;
     private int indentLevel;
@@ -250,7 +248,7 @@
     private static class AnnotationEndpoint {
         /** Annotations that are associated with a specific point between bytes */
         @Nonnull
-        public final List<AnnotationItem> pointAnnotations = Lists.newArrayList();
+        public final List<AnnotationItem> pointAnnotations = new ArrayList<>();
         /** Annotations that are associated with a range of bytes */
         @Nullable
         public AnnotationItem rangeAnnotation = null;
@@ -284,7 +282,7 @@
         int rightWidth = getAnnotationWidth();
         int leftWidth = outputWidth - rightWidth - 1;
 
-        String padding = Strings.repeat(" ", 1000);
+        String padding = StringUtils.repeat(" ", 1000);
 
         TwoColumnOutput twoc = new TwoColumnOutput(out, leftWidth, rightWidth, "|");
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/FieldUtil.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/FieldUtil.java
index a543b69..835d8a7 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/FieldUtil.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/FieldUtil.java
@@ -31,21 +31,21 @@
 package com.android.tools.smali.dexlib2.util;
 
 import com.android.tools.smali.dexlib2.iface.Field;
-import com.google.common.base.Predicate;
 import com.android.tools.smali.dexlib2.AccessFlags;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.function.Predicate;
 
 public final class FieldUtil {
     public static Predicate<Field> FIELD_IS_STATIC = new Predicate<Field>() {
-        @Override public boolean apply(@Nullable Field input) {
+        @Override public boolean test(@Nullable Field input) {
             return input!=null && isStatic(input);
         }
     };
 
     public static Predicate<Field> FIELD_IS_INSTANCE = new Predicate<Field>() {
-        @Override public boolean apply(@Nullable Field input) {
+        @Override public boolean test(@Nullable Field input) {
             return input!= null && !isStatic(input);
         }
     };
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/MethodUtil.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/MethodUtil.java
index 2c9812a..848544a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/MethodUtil.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/MethodUtil.java
@@ -30,7 +30,6 @@
 
 package com.android.tools.smali.dexlib2.util;
 
-import com.google.common.base.Predicate;
 import com.android.tools.smali.dexlib2.AccessFlags;
 import com.android.tools.smali.dexlib2.iface.Method;
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
@@ -39,19 +38,20 @@
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Collection;
+import java.util.function.Predicate;
 
 public final class MethodUtil {
     private static int directMask = AccessFlags.STATIC.getValue() | AccessFlags.PRIVATE.getValue() |
             AccessFlags.CONSTRUCTOR.getValue();
 
     public static Predicate<Method> METHOD_IS_DIRECT = new Predicate<Method>() {
-        @Override public boolean apply(@Nullable Method input) {
+        @Override public boolean test(@Nullable Method input) {
             return input != null && isDirect(input);
         }
     };
 
     public static Predicate<Method> METHOD_IS_VIRTUAL = new Predicate<Method>() {
-        @Override public boolean apply(@Nullable Method input) {
+        @Override public boolean test(@Nullable Method input) {
             return input != null && !isDirect(input);
         }
     };
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/SyntheticAccessorResolver.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/SyntheticAccessorResolver.java
index dadc9f6..543f2c0 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/SyntheticAccessorResolver.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/util/SyntheticAccessorResolver.java
@@ -33,20 +33,22 @@
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.iface.Method;
 import com.android.tools.smali.dexlib2.iface.MethodImplementation;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.Maps;
 import com.android.tools.smali.dexlib2.AccessFlags;
 import com.android.tools.smali.dexlib2.Opcodes;
 import com.android.tools.smali.dexlib2.iface.instruction.Instruction;
 import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction;
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
 import com.android.tools.smali.dexlib2.iface.reference.Reference;
+import com.android.tools.smali.util.IteratorUtils;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 public class SyntheticAccessorResolver {
     public static final int METHOD = 0;
@@ -70,17 +72,17 @@
 
     private final SyntheticAccessorFSM syntheticAccessorFSM;
     private final Map<String, ClassDef> classDefMap;
-    private final Map<MethodReference, AccessedMember> resolvedAccessors = Maps.newConcurrentMap();
+    private final Map<MethodReference, AccessedMember> resolvedAccessors = new ConcurrentHashMap<>();
 
     public SyntheticAccessorResolver(@Nonnull Opcodes opcodes, @Nonnull Iterable<? extends ClassDef> classDefs) {
         this.syntheticAccessorFSM = new SyntheticAccessorFSM(opcodes);
-        ImmutableMap.Builder<String, ClassDef> builder = ImmutableMap.builder();
+        HashMap<String, ClassDef> classDefMap = new HashMap<>();
 
         for (ClassDef classDef: classDefs) {
-            builder.put(classDef.getType(), classDef);
+            classDefMap.put(classDef.getType(), classDef);
         }
 
-        this.classDefMap = builder.build();
+        this.classDefMap = Collections.unmodifiableMap(classDefMap);
     }
 
     public static boolean looksLikeSyntheticAccessor(String methodName) {
@@ -122,7 +124,8 @@
             return null;
         }
 
-        List<Instruction> instructions = ImmutableList.copyOf(matchedMethodImpl.getInstructions());
+        List<Instruction> instructions = Collections.unmodifiableList(
+            IteratorUtils.toList(matchedMethodImpl.getInstructions()));
 
 
         int accessType = syntheticAccessorFSM.test(instructions);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/DebugInfoCache.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/DebugInfoCache.java
new file mode 100644
index 0000000..6bdfe55
--- /dev/null
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/DebugInfoCache.java
@@ -0,0 +1,30 @@
+package com.android.tools.smali.dexlib2.writer;
+
+import java.util.Arrays;
+
+public class DebugInfoCache {
+    private final byte[] data;
+    private final int threshold = 128;
+
+    public DebugInfoCache(byte[] data) {
+        this.data = data;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        DebugInfoCache that = (DebugInfoCache) o;
+        return Arrays.equals(data, that.data);
+    }
+
+    @Override
+    public int hashCode() {
+        int hashSize = Math.min(data.length, threshold);
+        int result = 0;
+        for (int i = 0; i < hashSize; i++) {
+          result = 31 * result + data[i];
+        }
+        return result;
+    }
+}
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/DexWriter.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/DexWriter.java
index 205ca2f..3e28b38 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/DexWriter.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/DexWriter.java
@@ -90,11 +90,6 @@
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
 import com.android.tools.smali.dexlib2.iface.reference.StringReference;
 import com.android.tools.smali.dexlib2.iface.reference.TypeReference;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Ordering;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.base.BaseAnnotation;
 import com.android.tools.smali.dexlib2.base.BaseAnnotationElement;
 import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation;
@@ -116,8 +111,12 @@
 import com.android.tools.smali.dexlib2.writer.io.DexDataStore;
 import com.android.tools.smali.dexlib2.writer.io.MemoryDeferredOutputStream;
 import com.android.tools.smali.dexlib2.writer.util.TryListBuilder;
+import com.android.tools.smali.util.ChainedIterator;
+import com.android.tools.smali.util.CollectionUtils;
 import com.android.tools.smali.util.ExceptionWithContext;
+import com.android.tools.smali.util.IteratorUtils;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -223,6 +222,8 @@
 
     private final IndexSection<?>[] overflowableSections;
 
+    private final Map<DebugInfoCache, Integer> debugInfoCaches = new HashMap<>();
+
     protected DexWriter(Opcodes opcodes) {
         this.opcodes = opcodes;
 
@@ -263,7 +264,7 @@
                 public int compare(Entry<? extends CallSiteKey, Integer> o1, Entry<? extends CallSiteKey, Integer> o2) {
                     int offset1 = encodedArraySection.getItemOffset(callSiteSection.getEncodedCallSite(o1.getKey()));
                     int offset2 = encodedArraySection.getItemOffset(callSiteSection.getEncodedCallSite(o2.getKey()));
-                    return Ints.compare(offset1, offset2);
+                    return Integer.compare(offset1, offset2);
                 }
             };
 
@@ -316,7 +317,7 @@
 
     @Nonnull
     public List<String> getMethodReferences() {
-        List<String> methodReferences = Lists.newArrayList();
+        List<String> methodReferences = new ArrayList<>();
         for (Entry<? extends MethodRefKey, Integer> methodReference: methodSection.getItems()) {
             methodReferences.add(DexFormatter.INSTANCE.getMethodDescriptor(methodReference.getKey()));
         }
@@ -325,7 +326,7 @@
 
     @Nonnull
     public List<String> getFieldReferences() {
-        List<String> fieldReferences = Lists.newArrayList();
+        List<String> fieldReferences = new ArrayList<>();
         for (Entry<? extends FieldRefKey, Integer> fieldReference: fieldSection.getItems()) {
             fieldReferences.add(DexFormatter.INSTANCE.getFieldDescriptor(fieldReference.getKey()));
         }
@@ -334,7 +335,7 @@
 
     @Nonnull
     public List<String> getTypeReferences() {
-        List<String> classReferences = Lists.newArrayList();
+        List<String> classReferences = new ArrayList<>();
         for (Entry<? extends TypeKey, Integer> typeReference: typeSection.getItems()) {
             classReferences.add(typeReference.getKey().toString());
         }
@@ -470,7 +471,7 @@
         stringIndexSectionOffset = indexWriter.getPosition();
         stringDataSectionOffset = offsetWriter.getPosition();
         int index = 0;
-        List<Entry<? extends StringKey, Integer>> stringEntries = Lists.newArrayList(stringSection.getItems());
+        List<Entry<? extends StringKey, Integer>> stringEntries = new ArrayList<>(stringSection.getItems());
         Collections.sort(stringEntries, toStringKeyComparator);
 
         for (Map.Entry<? extends StringKey, Integer>  entry: stringEntries) {
@@ -487,7 +488,7 @@
         typeSectionOffset = writer.getPosition();
         int index = 0;
 
-        List<Map.Entry<? extends TypeKey, Integer>> typeEntries = Lists.newArrayList(typeSection.getItems());
+        List<Map.Entry<? extends TypeKey, Integer>> typeEntries = new ArrayList<>(typeSection.getItems());
         Collections.sort(typeEntries, toStringKeyComparator);
 
         for (Map.Entry<? extends TypeKey, Integer> entry : typeEntries) {
@@ -500,7 +501,7 @@
         protoSectionOffset = writer.getPosition();
         int index = 0;
 
-        List<Map.Entry<? extends ProtoRefKey, Integer>> protoEntries = Lists.newArrayList(protoSection.getItems());
+        List<Map.Entry<? extends ProtoRefKey, Integer>> protoEntries = new ArrayList<>(protoSection.getItems());
         Collections.sort(protoEntries, DexWriter.<ProtoRefKey>comparableKeyComparator());
 
         for (Map.Entry<? extends ProtoRefKey, Integer> entry: protoEntries) {
@@ -516,7 +517,7 @@
         fieldSectionOffset = writer.getPosition();
         int index = 0;
 
-        List<Map.Entry<? extends FieldRefKey, Integer>> fieldEntries = Lists.newArrayList(fieldSection.getItems());
+        List<Map.Entry<? extends FieldRefKey, Integer>> fieldEntries = new ArrayList<>(fieldSection.getItems());
         Collections.sort(fieldEntries, DexWriter.<FieldRefKey>comparableKeyComparator());
         
         for (Map.Entry<? extends FieldRefKey, Integer> entry: fieldEntries) {
@@ -532,7 +533,7 @@
         methodSectionOffset = writer.getPosition();
         int index = 0;
 
-        List<Map.Entry<? extends MethodRefKey, Integer>> methodEntries = Lists.newArrayList(methodSection.getItems());
+        List<Map.Entry<? extends MethodRefKey, Integer>> methodEntries = new ArrayList<>(methodSection.getItems());
         Collections.sort(methodEntries, DexWriter.<MethodRefKey>comparableKeyComparator());
         
         for (Map.Entry<? extends MethodRefKey, Integer> entry: methodEntries) {
@@ -549,7 +550,7 @@
         classIndexSectionOffset = indexWriter.getPosition();
         classDataSectionOffset = offsetWriter.getPosition();
 
-        List<Map.Entry<? extends ClassKey, Integer>> classEntriesKeySorted = Lists.newArrayList(classSection.getItems());
+        List<Map.Entry<? extends ClassKey, Integer>> classEntriesKeySorted = new ArrayList<>(classSection.getItems());
         Collections.sort(classEntriesKeySorted, DexWriter.<ClassKey>comparableKeyComparator());
 
         int index = 0;
@@ -564,7 +565,7 @@
         offsetWriter.align();
         hiddenApiRestrictionsOffset = offsetWriter.getPosition();
 
-        List<Map.Entry<? extends ClassKey, Integer>> classEntriesValueSorted = Lists.newArrayList(classSection.getItems());
+        List<Map.Entry<? extends ClassKey, Integer>> classEntriesValueSorted = new ArrayList<>(classSection.getItems());
         classEntriesValueSorted.sort(DexWriter.comparableValueComparator());
         RestrictionsWriter restrictionsWriter = new RestrictionsWriter(dataStore, offsetWriter, classEntriesValueSorted.size());
 
@@ -765,7 +766,7 @@
         callSiteSectionOffset = writer.getPosition();
 
         List<Map.Entry<? extends CallSiteKey, Integer>> callSiteEntries =
-                Lists.newArrayList(callSiteSection.getItems());
+            new ArrayList<>(callSiteSection.getItems());
         Collections.sort(callSiteEntries, callSiteComparator);
 
         int index = 0;
@@ -883,8 +884,8 @@
             writer.writeUbyte(annotationSection.getVisibility(key));
             writer.writeUleb128(typeSection.getItemIndex(annotationSection.getType(key)));
 
-            Collection<? extends AnnotationElement> elements = Ordering.from(BaseAnnotationElement.BY_NAME)
-                    .immutableSortedCopy(annotationSection.getElements(key));
+            Collection<? extends AnnotationElement> elements = CollectionUtils.immutableSortedCopy(
+                annotationSection.getElements(key), BaseAnnotationElement.BY_NAME);
 
             writer.writeUleb128(elements.size());
 
@@ -902,9 +903,9 @@
             writer.writeInt(0);
         }
         for (Map.Entry<? extends AnnotationSetKey, Integer> entry: annotationSetSection.getItems()) {
-            Collection<? extends AnnotationKey> annotations = Ordering.from(BaseAnnotation.BY_TYPE)
-                    .immutableSortedCopy(annotationSetSection.getAnnotations(entry.getKey()));
-
+            Collection<? extends AnnotationKey> annotations = CollectionUtils.immutableSortedCopy(
+                    annotationSetSection.getAnnotations(entry.getKey()), BaseAnnotation.BY_TYPE);
+            
             writer.align();
             entry.setValue(writer.getPosition());
             writer.writeInt(annotations.size());
@@ -917,7 +918,7 @@
     private void writeAnnotationSetRefs(@Nonnull DexDataWriter writer) throws IOException {
         writer.align();
         annotationSetRefSectionOffset = writer.getPosition();
-        HashMap<List<? extends AnnotationSetKey>, Integer> internedItems = Maps.newHashMap();
+        HashMap<List<? extends AnnotationSetKey>, Integer> internedItems = new HashMap<>();
 
         for (ClassKey classKey: classSection.getSortedClasses()) {
             for (MethodKey methodKey: classSection.getSortedMethods(classKey)) {
@@ -953,7 +954,7 @@
     private void writeAnnotationDirectories(@Nonnull DexDataWriter writer) throws IOException {
         writer.align();
         annotationDirectorySectionOffset = writer.getPosition();
-        HashMap<AnnotationSetKey, Integer> internedItems = Maps.newHashMap();
+        HashMap<AnnotationSetKey, Integer> internedItems = new HashMap<>();
 
         ByteBuffer tempBuffer = ByteBuffer.allocate(65536);
         tempBuffer.order(ByteOrder.LITTLE_ENDIAN);
@@ -1049,18 +1050,17 @@
                                         @Nonnull DeferredOutputStream temp) throws IOException {
         ByteArrayOutputStream ehBuf = new ByteArrayOutputStream();
         debugSectionOffset = offsetWriter.getPosition();
-        DebugWriter<StringKey, TypeKey> debugWriter =
-                new DebugWriter<StringKey, TypeKey>(stringSection, typeSection, offsetWriter);
 
         DexDataWriter codeWriter = new DexDataWriter(temp, 0);
 
-        List<CodeItemOffset<MethodKey>> codeOffsets = Lists.newArrayList();
+        List<CodeItemOffset<MethodKey>> codeOffsets = new ArrayList<>();
 
         for (ClassKey classKey: classSection.getSortedClasses()) {
             Collection<? extends MethodKey> directMethods = classSection.getSortedDirectMethods(classKey);
             Collection<? extends MethodKey> virtualMethods = classSection.getSortedVirtualMethods(classKey);
 
-            Iterable<MethodKey> methods = Iterables.concat(directMethods, virtualMethods);
+            Iterable<MethodKey> methods = new ChainedIterator<MethodKey>(
+                (Collection<MethodKey>)directMethods, (Collection<MethodKey>)virtualMethods);
 
             for (MethodKey methodKey: methods) {
                 List<? extends TryBlock<? extends ExceptionHandler>> tryBlocks =
@@ -1091,8 +1091,7 @@
                     }
                 }
 
-                int debugItemOffset = writeDebugItem(offsetWriter, debugWriter,
-                        classSection.getParameterNames(methodKey), debugItems);
+                int debugItemOffset = writeDebugItem(offsetWriter, classSection.getParameterNames(methodKey), debugItems);
                 int codeItemOffset;
                 try {
                     codeItemOffset = writeCodeItem(
@@ -1138,13 +1137,12 @@
     }
 
     private int writeDebugItem(@Nonnull DexDataWriter writer,
-                               @Nonnull DebugWriter<StringKey, TypeKey> debugWriter,
                                @Nullable Iterable<? extends StringKey> parameterNames,
                                @Nullable Iterable<? extends DebugItem> debugItems) throws IOException {
         int parameterCount = 0;
         int lastNamedParameterIndex = -1;
         if (parameterNames != null) {
-            parameterCount = Iterables.size(parameterNames);
+            parameterCount = IteratorUtils.size(parameterNames);
             int index = 0;
             for (StringKey parameterName: parameterNames) {
                 if (parameterName != null) {
@@ -1155,12 +1153,11 @@
         }
 
 
-        if (lastNamedParameterIndex == -1 && (debugItems == null || Iterables.isEmpty(debugItems))) {
+        if (lastNamedParameterIndex == -1 && (debugItems == null 
+                || !debugItems.iterator().hasNext())) {
             return NO_OFFSET;
         }
 
-        numDebugInfoItems++;
-
         int debugItemOffset = writer.getPosition();
         int startingLineNumber = 0;
 
@@ -1172,9 +1169,14 @@
                 }
             }
         }
-        writer.writeUleb128(startingLineNumber);
 
-        writer.writeUleb128(parameterCount);
+        ByteArrayOutputStream tempByteOutput = new ByteArrayOutputStream();
+        DexDataWriter tempDataWriter = new DexDataWriter(tempByteOutput, 0, 64);
+        DebugWriter tempDebugWriter = new DebugWriter(stringSection, typeSection, tempDataWriter);
+
+        tempDataWriter.writeUleb128(startingLineNumber);
+
+        tempDataWriter.writeUleb128(parameterCount);
         if (parameterNames != null) {
             int index = 0;
             for (StringKey parameterName: parameterNames) {
@@ -1182,21 +1184,32 @@
                     break;
                 }
                 index++;
-                writer.writeUleb128(stringSection.getNullableItemIndex(parameterName) + 1);
+                tempDataWriter.writeUleb128(stringSection.getNullableItemIndex(parameterName) + 1);
             }
         }
 
         if (debugItems != null) {
-            debugWriter.reset(startingLineNumber);
+            tempDebugWriter.reset(startingLineNumber);
 
             for (DebugItem debugItem: debugItems) {
-                classSection.writeDebugItem(debugWriter, debugItem);
+                classSection.writeDebugItem(tempDebugWriter, debugItem);
             }
         }
         // write an END_SEQUENCE opcode, to end the debug item
-        writer.write(0);
+        tempDataWriter.write(0);
 
-        return debugItemOffset;
+        tempDataWriter.flush();
+        byte[] debugInfo = tempByteOutput.toByteArray();
+        DebugInfoCache wrapBytes = new DebugInfoCache(debugInfo);
+        int cacheBytes = debugInfoCaches.getOrDefault(wrapBytes, -1);
+        if (cacheBytes >= 0) {
+            return cacheBytes;
+        } else {
+            writer.write(debugInfo);
+            debugInfoCaches.put(wrapBytes, debugItemOffset);
+            numDebugInfoItems++;
+            return debugItemOffset;
+        }
     }
 
     private int writeCodeItem(@Nonnull DexDataWriter writer,
@@ -1381,7 +1394,7 @@
                 writer.align();
 
                 // filter out unique lists of exception handlers
-                Map<List<? extends ExceptionHandler>, Integer> exceptionHandlerOffsetMap = Maps.newHashMap();
+                Map<List<? extends ExceptionHandler>, Integer> exceptionHandlerOffsetMap = new HashMap<>();
                 for (TryBlock<? extends ExceptionHandler> tryBlock: tryBlocks) {
                     exceptionHandlerOffsetMap.put(tryBlock.getExceptionHandlers(), 0);
                 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/EncodedValueWriter.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/EncodedValueWriter.java
index 77c647b..890a13a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/EncodedValueWriter.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/EncodedValueWriter.java
@@ -30,16 +30,19 @@
 
 package com.android.tools.smali.dexlib2.writer;
 
-import com.google.common.collect.Ordering;
 import com.android.tools.smali.dexlib2.ValueType;
 import com.android.tools.smali.dexlib2.base.BaseAnnotationElement;
 import com.android.tools.smali.dexlib2.iface.reference.FieldReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodHandleReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
+import com.android.tools.smali.util.CollectionUtils;
 
 import javax.annotation.Nonnull;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Collection;
+import java.util.Collections;
 
 public abstract class EncodedValueWriter<StringKey, TypeKey, FieldRefKey extends FieldReference,
         MethodRefKey extends MethodReference, AnnotationElement extends com.android.tools.smali.dexlib2.iface.AnnotationElement,
@@ -80,8 +83,8 @@
         writer.writeUleb128(typeSection.getItemIndex(annotationType));
         writer.writeUleb128(elements.size());
 
-        Collection<? extends AnnotationElement> sortedElements = Ordering.from(BaseAnnotationElement.BY_NAME)
-                .immutableSortedCopy(elements);
+        List<? extends AnnotationElement> sortedElements = CollectionUtils.immutableSortedCopy(
+                elements, BaseAnnotationElement.BY_NAME);
 
         for (AnnotationElement element: sortedElements) {
             writer.writeUleb128(stringSection.getItemIndex(annotationSection.getElementName(element)));
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/InstructionWriter.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/InstructionWriter.java
index 0aa674f..795e931 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/InstructionWriter.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/InstructionWriter.java
@@ -74,18 +74,19 @@
 import com.android.tools.smali.dexlib2.iface.reference.Reference;
 import com.android.tools.smali.dexlib2.iface.reference.StringReference;
 import com.android.tools.smali.dexlib2.iface.reference.TypeReference;
-import com.google.common.collect.Ordering;
-import com.google.common.primitives.Ints;
 import com.android.tools.smali.dexlib2.Opcode;
 import com.android.tools.smali.dexlib2.Opcodes;
 import com.android.tools.smali.dexlib2.ReferenceType;
 import com.android.tools.smali.dexlib2.iface.instruction.DualReferenceInstruction;
 import com.android.tools.smali.dexlib2.iface.instruction.ReferenceInstruction;
 import com.android.tools.smali.dexlib2.iface.instruction.SwitchElement;
+import com.android.tools.smali.util.CollectionUtils;
 import com.android.tools.smali.util.ExceptionWithContext;
 
 import javax.annotation.Nonnull;
 import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 
@@ -535,8 +536,9 @@
         try {
             writer.writeUbyte(0);
             writer.writeUbyte(getOpcodeValue(instruction.getOpcode()) >> 8);
-            List<? extends SwitchElement> elements = Ordering.from(switchElementComparator).immutableSortedCopy(
-                    instruction.getSwitchElements());
+            List<? extends SwitchElement> elements = CollectionUtils.immutableSortedCopy(
+                    instruction.getSwitchElements(), switchElementComparator);
+
             writer.writeUshort(elements.size());
             for (SwitchElement element: elements) {
                 writer.writeInt(element.getKey());
@@ -551,7 +553,7 @@
 
     private final Comparator<SwitchElement> switchElementComparator = new Comparator<SwitchElement>() {
         @Override public int compare(SwitchElement element1, SwitchElement element2) {
-            return Ints.compare(element1.getKey(), element2.getKey());
+            return Integer.compare(element1.getKey(), element2.getKey());
         }
     };
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderAnnotationPool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderAnnotationPool.java
index 637dd05..4d3e107 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderAnnotationPool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderAnnotationPool.java
@@ -32,18 +32,18 @@
 
 import com.android.tools.smali.dexlib2.iface.Annotation;
 import com.android.tools.smali.dexlib2.writer.AnnotationSection;
-import com.google.common.collect.Maps;
 import com.android.tools.smali.dexlib2.writer.builder.BuilderEncodedValues.BuilderEncodedValue;
 
 import javax.annotation.Nonnull;
 import java.util.Collection;
 import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 class BuilderAnnotationPool extends BaseBuilderPool implements AnnotationSection<BuilderStringReference,
         BuilderTypeReference, BuilderAnnotation, BuilderAnnotationElement, BuilderEncodedValue> {
     @Nonnull private final ConcurrentMap<Annotation, BuilderAnnotation> internedItems =
-            Maps.newConcurrentMap();
+            new ConcurrentHashMap<>();
 
     public BuilderAnnotationPool(@Nonnull DexBuilder dexBuilder) {
         super(dexBuilder);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderAnnotationSet.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderAnnotationSet.java
index ae28130..915e771 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderAnnotationSet.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderAnnotationSet.java
@@ -31,16 +31,16 @@
 package com.android.tools.smali.dexlib2.writer.builder;
 
 import com.android.tools.smali.dexlib2.writer.DexWriter;
-import com.google.common.collect.ImmutableSet;
 
 import javax.annotation.Nonnull;
 import java.util.AbstractSet;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.Set;
 
 public class BuilderAnnotationSet extends AbstractSet<BuilderAnnotation> {
     public static final BuilderAnnotationSet EMPTY =
-            new BuilderAnnotationSet(ImmutableSet.<BuilderAnnotation>of());
+            new BuilderAnnotationSet(Collections.emptySet());
 
     @Nonnull final Set<BuilderAnnotation> annotations;
     int offset = DexWriter.NO_OFFSET;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderAnnotationSetPool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderAnnotationSetPool.java
index eacb472..f53e943 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderAnnotationSetPool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderAnnotationSetPool.java
@@ -33,22 +33,21 @@
 import com.android.tools.smali.dexlib2.iface.Annotation;
 import com.android.tools.smali.dexlib2.writer.AnnotationSetSection;
 import com.android.tools.smali.dexlib2.writer.DexWriter;
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.Iterators;
-import com.google.common.collect.Maps;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Map.Entry;
 import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
+import java.util.stream.Collectors;
 
 class BuilderAnnotationSetPool extends BaseBuilderPool
         implements AnnotationSetSection<BuilderAnnotation, BuilderAnnotationSet> {
     @Nonnull private final ConcurrentMap<Set<? extends Annotation>, BuilderAnnotationSet> internedItems =
-            Maps.newConcurrentMap();
+            new ConcurrentHashMap<>();
 
     public BuilderAnnotationSetPool(@Nonnull DexBuilder dexBuilder) {
         super(dexBuilder);
@@ -65,12 +64,9 @@
         }
 
         BuilderAnnotationSet annotationSet = new BuilderAnnotationSet(
-                ImmutableSet.copyOf(Iterators.transform(annotations.iterator(),
-                        new Function<Annotation, BuilderAnnotation>() {
-                            @Nullable @Override public BuilderAnnotation apply(Annotation input) {
-                                return dexBuilder.annotationSection.internAnnotation(input);
-                            }
-                        })));
+            Collections.unmodifiableSet(annotations.stream()
+                .map(annotation -> dexBuilder.annotationSection.internAnnotation(annotation))
+                .collect(Collectors.toSet())));
 
         ret = internedItems.putIfAbsent(annotationSet, annotationSet);
         return ret==null?annotationSet:ret;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderCallSitePool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderCallSitePool.java
index df7a198..23bf45e 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderCallSitePool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderCallSitePool.java
@@ -32,19 +32,19 @@
 
 import com.android.tools.smali.dexlib2.writer.CallSiteSection;
 import com.android.tools.smali.dexlib2.writer.builder.BuilderEncodedValues.BuilderArrayEncodedValue;
-import com.google.common.collect.Maps;
 import com.android.tools.smali.dexlib2.iface.reference.CallSiteReference;
 import com.android.tools.smali.dexlib2.writer.util.CallSiteUtil;
 
 import javax.annotation.Nonnull;
 import java.util.Collection;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 public class BuilderCallSitePool extends BaseBuilderPool
         implements CallSiteSection<BuilderCallSiteReference, BuilderArrayEncodedValue> {
     @Nonnull private final ConcurrentMap<CallSiteReference, BuilderCallSiteReference> internedItems =
-            Maps.newConcurrentMap();
+            new ConcurrentHashMap<>();
 
     public BuilderCallSitePool(@Nonnull DexBuilder dexBuilder) {
         super(dexBuilder);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderCallSiteReference.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderCallSiteReference.java
index 7580303..a610e57 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderCallSiteReference.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderCallSiteReference.java
@@ -31,7 +31,6 @@
 package com.android.tools.smali.dexlib2.writer.builder;
 
 import com.android.tools.smali.dexlib2.writer.DexWriter;
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.base.reference.BaseCallSiteReference;
 import com.android.tools.smali.dexlib2.iface.value.StringEncodedValue;
 import com.android.tools.smali.dexlib2.writer.builder.BuilderEncodedValues.BuilderArrayEncodedValue;
@@ -40,6 +39,7 @@
 import com.android.tools.smali.dexlib2.writer.builder.BuilderEncodedValues.BuilderMethodTypeEncodedValue;
 
 import javax.annotation.Nonnull;
+import java.util.Collections;
 import java.util.List;
 
 public class BuilderCallSiteReference extends BaseCallSiteReference implements BuilderReference {
@@ -71,7 +71,7 @@
 
     @Nonnull @Override public List<? extends BuilderEncodedValue> getExtraArguments() {
         if (encodedCallSite.elements.size() <= 3) {
-            return ImmutableList.of();
+            return Collections.emptyList();
         }
         return encodedCallSite.elements.subList(3, encodedCallSite.elements.size());
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderClassDef.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderClassDef.java
index 43375b1..b6d0c29 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderClassDef.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderClassDef.java
@@ -33,21 +33,20 @@
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.util.MethodUtil;
 import com.android.tools.smali.dexlib2.writer.DexWriter;
-import com.google.common.base.Functions;
 import com.android.tools.smali.dexlib2.base.reference.BaseTypeReference;
 import com.android.tools.smali.dexlib2.writer.builder.BuilderEncodedValues.BuilderArrayEncodedValue;
+import com.android.tools.smali.util.ArraySortedSet;
+import com.android.tools.smali.util.CollectionUtils;
+import com.android.tools.smali.util.IteratorUtils;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Iterators;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Ordering;
 import java.util.AbstractCollection;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.SortedSet;
+import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
@@ -78,13 +77,13 @@
                     @Nullable Iterable<? extends BuilderMethod> methods,
                     @Nullable BuilderArrayEncodedValue staticInitializers) {
         if (methods == null) {
-            methods = ImmutableList.of();
+            methods = Collections.emptyList();
         }
         if (staticFields == null) {
-            staticFields = ImmutableSortedSet.of();
+            staticFields = Collections.emptySortedSet();
         }
         if (instanceFields == null) {
-            instanceFields = ImmutableSortedSet.of();
+            instanceFields = Collections.emptySortedSet();
         }
 
         this.type = type;
@@ -95,8 +94,10 @@
         this.annotations = annotations;
         this.staticFields = staticFields;
         this.instanceFields = instanceFields;
-        this.directMethods = ImmutableSortedSet.copyOf(Iterables.filter(methods, MethodUtil.METHOD_IS_DIRECT));
-        this.virtualMethods = ImmutableSortedSet.copyOf(Iterables.filter(methods, MethodUtil.METHOD_IS_VIRTUAL));
+        this.directMethods = ArraySortedSet.copyOf(CollectionUtils.naturalOrdering(), IteratorUtils.toList(
+                (Iterator<? extends BuilderMethod>)IteratorUtils.filter(methods, MethodUtil.METHOD_IS_DIRECT)));
+        this.virtualMethods = ArraySortedSet.copyOf(CollectionUtils.naturalOrdering(), IteratorUtils.toList(
+                (Iterator<? extends BuilderMethod>)IteratorUtils.filter(methods, MethodUtil.METHOD_IS_VIRTUAL)));
         this.staticInitializers = staticInitializers;
     }
 
@@ -112,15 +113,18 @@
 
     @Nonnull @Override
     public List<String> getInterfaces() {
-        return Lists.transform(this.interfaces, Functions.toStringFunction());
+        return this.interfaces.stream()
+                .map(iface -> iface.toString())
+                .collect(Collectors.toList());
     }
 
     @Nonnull @Override public Collection<BuilderField> getFields() {
         return new AbstractCollection<BuilderField>() {
             @Nonnull @Override public Iterator<BuilderField> iterator() {
-                return Iterators.mergeSorted(
-                        ImmutableList.of(staticFields.iterator(), instanceFields.iterator()),
-                        Ordering.natural());
+                ArrayList<BuilderField> fields = new ArrayList<>(staticFields);
+                fields.addAll(instanceFields);
+                Collections.sort(fields, CollectionUtils.naturalOrdering());
+                return fields.iterator();
             }
 
             @Override public int size() {
@@ -132,9 +136,10 @@
     @Nonnull @Override public Collection<BuilderMethod> getMethods() {
         return new AbstractCollection<BuilderMethod>() {
             @Nonnull @Override public Iterator<BuilderMethod> iterator() {
-                return Iterators.mergeSorted(
-                        ImmutableList.of(directMethods.iterator(), virtualMethods.iterator()),
-                        Ordering.natural());
+                ArrayList<BuilderMethod> methods = new ArrayList<>(directMethods);
+                methods.addAll(virtualMethods);
+                Collections.sort(methods, CollectionUtils.naturalOrdering());
+                return methods.iterator();
             }
 
             @Override public int size() {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderClassPool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderClassPool.java
index 0b6f92e..25f780f 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderClassPool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderClassPool.java
@@ -46,9 +46,8 @@
 import com.android.tools.smali.dexlib2.writer.ClassSection;
 import com.android.tools.smali.dexlib2.writer.DebugWriter;
 import com.android.tools.smali.util.AbstractForwardSequentialList;
+import com.android.tools.smali.util.CollectionUtils;
 import com.android.tools.smali.util.ExceptionWithContext;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
 import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation;
 import com.android.tools.smali.dexlib2.iface.instruction.Instruction;
 import com.android.tools.smali.dexlib2.iface.reference.StringReference;
@@ -57,16 +56,17 @@
 import com.android.tools.smali.dexlib2.writer.builder.BuilderEncodedValues.BuilderArrayEncodedValue;
 import com.android.tools.smali.dexlib2.writer.builder.BuilderEncodedValues.BuilderEncodedValue;
 
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Ordering;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.io.IOException;
@@ -77,7 +77,7 @@
         BuilderTypeReference, BuilderTypeList, BuilderClassDef, BuilderField, BuilderMethod, BuilderAnnotationSet,
         BuilderArrayEncodedValue> {
     @Nonnull private final ConcurrentMap<String, BuilderClassDef> internedItems =
-            Maps.newConcurrentMap();
+            new ConcurrentHashMap<>();
 
     public BuilderClassPool(@Nonnull DexBuilder dexBuilder) {
         super(dexBuilder);
@@ -91,10 +91,11 @@
         return classDef;
     }
 
-    private ImmutableList<BuilderClassDef> sortedClasses = null;
+    private List<BuilderClassDef> sortedClasses = null;
     @Nonnull @Override public Collection<? extends BuilderClassDef> getSortedClasses() {
         if (sortedClasses == null) {
-            sortedClasses = Ordering.natural().immutableSortedCopy(internedItems.values());
+            sortedClasses = CollectionUtils.immutableSortedCopy(
+                    internedItems.values(), CollectionUtils.naturalOrdering());
         }
         return sortedClasses;
     }
@@ -147,7 +148,7 @@
 
     private static final Predicate<Field> HAS_INITIALIZER = new Predicate<Field>() {
         @Override
-        public boolean apply(Field input) {
+        public boolean test(Field input) {
             EncodedValue encodedValue = input.getInitialValue();
             return encodedValue != null && !EncodedValueUtils.isDefaultValue(encodedValue);
         }
@@ -242,7 +243,7 @@
     private static final Predicate<BuilderMethodParameter> HAS_PARAMETER_ANNOTATIONS =
             new Predicate<BuilderMethodParameter>() {
                 @Override
-                public boolean apply(BuilderMethodParameter input) {
+                public boolean test(BuilderMethodParameter input) {
                     return input.getAnnotations().size() > 0;
                 }
             };
@@ -258,13 +259,12 @@
     @Nullable @Override public List<? extends BuilderAnnotationSet> getParameterAnnotations(
             @Nonnull final BuilderMethod method) {
         final List<? extends BuilderMethodParameter> parameters = method.getParameters();
-        boolean hasParameterAnnotations = Iterables.any(parameters, HAS_PARAMETER_ANNOTATIONS);
+        boolean hasParameterAnnotations = parameters.stream().anyMatch(HAS_PARAMETER_ANNOTATIONS);
 
         if (hasParameterAnnotations) {
             return new AbstractForwardSequentialList<BuilderAnnotationSet>() {
                 @Nonnull @Override public Iterator<BuilderAnnotationSet> iterator() {
-                    return FluentIterable.from(parameters)
-                            .transform(PARAMETER_ANNOTATIONS).iterator();
+                    return parameters.stream().map(PARAMETER_ANNOTATIONS).iterator();
                 }
 
                 @Override public int size() {
@@ -286,11 +286,8 @@
 
     @Nullable @Override
     public Iterable<? extends BuilderStringReference> getParameterNames(@Nonnull BuilderMethod method) {
-        return Iterables.transform(method.getParameters(), new Function<BuilderMethodParameter, BuilderStringReference>() {
-            @Nullable @Override public BuilderStringReference apply(BuilderMethodParameter input) {
-                return input.name;
-            }
-        });
+        return method.getParameters().stream().map(
+            builderMethodParameter -> builderMethodParameter.name).collect(Collectors.toList());
     }
 
     @Override public int getRegisterCount(@Nonnull BuilderMethod builderMethod) {
@@ -314,7 +311,7 @@
     public List<? extends TryBlock<? extends ExceptionHandler>> getTryBlocks(@Nonnull BuilderMethod builderMethod) {
         MethodImplementation impl = builderMethod.getImplementation();
         if (impl == null) {
-            return ImmutableList.of();
+            return Collections.emptyList();
         }
         return impl.getTryBlocks();
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderEncodedArrayPool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderEncodedArrayPool.java
index d5a0e46..db390d9 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderEncodedArrayPool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderEncodedArrayPool.java
@@ -33,19 +33,19 @@
 import com.android.tools.smali.dexlib2.writer.EncodedArraySection;
 import com.android.tools.smali.dexlib2.writer.builder.BuilderEncodedValues.BuilderArrayEncodedValue;
 import com.android.tools.smali.dexlib2.writer.builder.BuilderEncodedValues.BuilderEncodedValue;
-import com.google.common.collect.Maps;
 import com.android.tools.smali.dexlib2.iface.value.ArrayEncodedValue;
 
 import javax.annotation.Nonnull;
 import java.util.Collection;
 import java.util.List;
 import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 public class BuilderEncodedArrayPool extends BaseBuilderPool implements
     EncodedArraySection<BuilderArrayEncodedValue, BuilderEncodedValue> {
     @Nonnull private final ConcurrentMap<ArrayEncodedValue, BuilderArrayEncodedValue> internedItems =
-            Maps.newConcurrentMap();
+            new ConcurrentHashMap<>();
 
     public BuilderEncodedArrayPool(@Nonnull DexBuilder dexBuilder) {
         super(dexBuilder);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderFieldPool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderFieldPool.java
index 1cba226..32d0037 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderFieldPool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderFieldPool.java
@@ -32,19 +32,19 @@
 
 import com.android.tools.smali.dexlib2.immutable.reference.ImmutableFieldReference;
 import com.android.tools.smali.dexlib2.writer.FieldSection;
-import com.google.common.collect.Maps;
 import com.android.tools.smali.dexlib2.iface.reference.FieldReference;
 
 import javax.annotation.Nonnull;
 import java.util.Collection;
 import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 public class BuilderFieldPool extends BaseBuilderPool
         implements
     FieldSection<BuilderStringReference, BuilderTypeReference, BuilderFieldReference, BuilderField> {
     @Nonnull private final ConcurrentMap<FieldReference, BuilderFieldReference> internedItems =
-            Maps.newConcurrentMap();
+            new ConcurrentHashMap<>();
 
     public BuilderFieldPool(@Nonnull DexBuilder dexBuilder) {
         super(dexBuilder);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderMethodHandlePool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderMethodHandlePool.java
index e63c993..76b6b08 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderMethodHandlePool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderMethodHandlePool.java
@@ -33,13 +33,13 @@
 import com.android.tools.smali.dexlib2.MethodHandleType;
 import com.android.tools.smali.dexlib2.writer.MethodHandleSection;
 import com.android.tools.smali.util.ExceptionWithContext;
-import com.google.common.collect.Maps;
 import com.android.tools.smali.dexlib2.iface.reference.FieldReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodHandleReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
 
 import javax.annotation.Nonnull;
 import java.util.Collection;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.Map;
 import java.util.concurrent.ConcurrentMap;
 
@@ -47,7 +47,7 @@
         implements
     MethodHandleSection<BuilderMethodHandleReference, BuilderFieldReference, BuilderMethodReference> {
     @Nonnull private final ConcurrentMap<MethodHandleReference, BuilderMethodHandleReference> internedItems =
-            Maps.newConcurrentMap();
+            new ConcurrentHashMap<>();;
 
     public BuilderMethodHandlePool(@Nonnull DexBuilder dexBuilder) {
         super(dexBuilder);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderMethodPool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderMethodPool.java
index 725de9e..cf8ef1e 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderMethodPool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderMethodPool.java
@@ -31,7 +31,6 @@
 package com.android.tools.smali.dexlib2.writer.builder;
 
 import com.android.tools.smali.dexlib2.writer.MethodSection;
-import com.google.common.collect.Maps;
 import com.android.tools.smali.dexlib2.base.reference.BaseMethodReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
 
@@ -39,12 +38,13 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 class BuilderMethodPool extends BaseBuilderPool implements MethodSection<BuilderStringReference, BuilderTypeReference,
         BuilderMethodProtoReference, BuilderMethodReference, BuilderMethod> {
     @Nonnull private final ConcurrentMap<MethodReference, BuilderMethodReference> internedItems =
-            Maps.newConcurrentMap();
+            new ConcurrentHashMap<>();
 
     public BuilderMethodPool(@Nonnull DexBuilder dexBuilder) {
         super(dexBuilder);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderProtoPool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderProtoPool.java
index 00f0ed1..027a924 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderProtoPool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderProtoPool.java
@@ -33,7 +33,6 @@
 import com.android.tools.smali.dexlib2.immutable.reference.ImmutableMethodProtoReference;
 import com.android.tools.smali.dexlib2.util.MethodUtil;
 import com.android.tools.smali.dexlib2.writer.ProtoSection;
-import com.google.common.collect.Maps;
 import com.android.tools.smali.dexlib2.iface.reference.MethodProtoReference;
 import com.android.tools.smali.dexlib2.iface.reference.MethodReference;
 
@@ -41,13 +40,14 @@
 import javax.annotation.Nullable;
 import java.util.Collection;
 import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 class BuilderProtoPool extends BaseBuilderPool
         implements
     ProtoSection<BuilderStringReference, BuilderTypeReference, BuilderMethodProtoReference, BuilderTypeList> {
     @Nonnull private final ConcurrentMap<MethodProtoReference, BuilderMethodProtoReference> internedItems =
-            Maps.newConcurrentMap();
+            new ConcurrentHashMap<>();
 
     public BuilderProtoPool(@Nonnull DexBuilder dexBuilder) {
         super(dexBuilder);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderStringPool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderStringPool.java
index 406da02..ac2fa64 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderStringPool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderStringPool.java
@@ -32,16 +32,16 @@
 
 import com.android.tools.smali.dexlib2.writer.DexWriter;
 import com.android.tools.smali.dexlib2.writer.StringSection;
-import com.google.common.collect.Maps;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Collection;
 import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 class BuilderStringPool implements StringSection<BuilderStringReference, BuilderStringReference> {
-    @Nonnull private final ConcurrentMap<String, BuilderStringReference> internedItems = Maps.newConcurrentMap();
+    @Nonnull private final ConcurrentMap<String, BuilderStringReference> internedItems = new ConcurrentHashMap<>();
 
     @Nonnull BuilderStringReference internString(@Nonnull String string) {
         BuilderStringReference ret = internedItems.get(string);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderTypeList.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderTypeList.java
index 0cb9b7e..7dbec16 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderTypeList.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderTypeList.java
@@ -31,14 +31,14 @@
 package com.android.tools.smali.dexlib2.writer.builder;
 
 import com.android.tools.smali.dexlib2.writer.DexWriter;
-import com.google.common.collect.ImmutableList;
 
 import javax.annotation.Nonnull;
 import java.util.AbstractList;
+import java.util.Collections;
 import java.util.List;
 
 public class BuilderTypeList extends AbstractList<BuilderTypeReference> {
-    static final BuilderTypeList EMPTY = new BuilderTypeList(ImmutableList.<BuilderTypeReference>of());
+    static final BuilderTypeList EMPTY = new BuilderTypeList(Collections.emptyList());
 
     @Nonnull final List<? extends BuilderTypeReference> types;
     int offset = DexWriter.NO_OFFSET;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderTypeListPool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderTypeListPool.java
index 4b7942b..049463e 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderTypeListPool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderTypeListPool.java
@@ -32,22 +32,21 @@
 
 import com.android.tools.smali.dexlib2.writer.DexWriter;
 import com.android.tools.smali.dexlib2.writer.TypeListSection;
-import com.google.common.base.Function;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Maps;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 import java.util.Map.Entry;
+import java.util.stream.Collectors;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 class BuilderTypeListPool extends BaseBuilderPool implements
     TypeListSection<BuilderTypeReference, BuilderTypeList> {
     @Nonnull private final ConcurrentMap<List<? extends CharSequence>, BuilderTypeList> internedItems =
-            Maps.newConcurrentMap();
+            new ConcurrentHashMap<>();
 
     public BuilderTypeListPool(@Nonnull DexBuilder dexBuilder) {
         super(dexBuilder);
@@ -64,11 +63,10 @@
         }
 
         BuilderTypeList typeList = new BuilderTypeList(
-                ImmutableList.copyOf(Iterables.transform(types, new Function<CharSequence, BuilderTypeReference>() {
-                    @Nonnull @Override public BuilderTypeReference apply(CharSequence input) {
-                        return dexBuilder.typeSection.internType(input.toString());
-                    }
-                })));
+            Collections.unmodifiableList(
+                types.stream()
+                        .map(type -> dexBuilder.typeSection.internType(type.toString()))
+                        .collect(Collectors.toList())));
 
         ret = internedItems.putIfAbsent(typeList, typeList);
         return ret==null?typeList:ret;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderTypePool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderTypePool.java
index dfd6c20..a14dcaa 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderTypePool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/BuilderTypePool.java
@@ -32,17 +32,17 @@
 
 import com.android.tools.smali.dexlib2.writer.DexWriter;
 import com.android.tools.smali.dexlib2.writer.TypeSection;
-import com.google.common.collect.Maps;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Collection;
 import java.util.Map.Entry;
+import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 
 class BuilderTypePool extends BaseBuilderPool
         implements TypeSection<BuilderStringReference, BuilderTypeReference, BuilderTypeReference> {
-    @Nonnull private final ConcurrentMap<String, BuilderTypeReference> internedItems = Maps.newConcurrentMap();
+    @Nonnull private final ConcurrentMap<String, BuilderTypeReference> internedItems = new ConcurrentHashMap<>();
 
     public BuilderTypePool(@Nonnull DexBuilder dexBuilder) {
         super(dexBuilder);
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/DexBuilder.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/DexBuilder.java
index cd54a6e..1b1abcc 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/DexBuilder.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/builder/DexBuilder.java
@@ -84,22 +84,24 @@
 import com.android.tools.smali.dexlib2.writer.builder.BuilderEncodedValues.BuilderShortEncodedValue;
 import com.android.tools.smali.dexlib2.writer.builder.BuilderEncodedValues.BuilderStringEncodedValue;
 import com.android.tools.smali.dexlib2.writer.builder.BuilderEncodedValues.BuilderTypeEncodedValue;
+import com.android.tools.smali.util.ArraySortedSet;
+import com.android.tools.smali.util.CollectionUtils;
 import com.android.tools.smali.util.ExceptionWithContext;
-import com.google.common.base.Function;
+import com.android.tools.smali.util.IteratorUtils;
+import com.android.tools.smali.util.TransformedIterator;
 import com.android.tools.smali.dexlib2.writer.util.StaticInitializerUtil;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Iterators;
-import com.google.common.collect.Sets;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.io.IOException;
+import java.util.Collections;
+import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.SortedSet;
+import java.util.function.Function;
+import java.util.stream.Collectors;
 
 public class DexBuilder extends DexWriter<BuilderStringReference, BuilderStringReference, BuilderTypeReference,
         BuilderTypeReference, BuilderMethodProtoReference, BuilderFieldReference, BuilderMethodReference,
@@ -140,7 +142,7 @@
                                                @Nonnull Set<HiddenApiRestriction> hiddenApiRestrictions,
                                                @Nullable MethodImplementation methodImplementation) {
         if (parameters == null) {
-            parameters = ImmutableList.of();
+            parameters = Collections.emptyList();
         }
         return new BuilderMethod(methodSection.internMethod(definingClass, name, parameters, returnType),
                 internMethodParameters(parameters),
@@ -159,9 +161,9 @@
                                                    @Nullable Iterable<? extends BuilderField> fields,
                                                    @Nullable Iterable<? extends BuilderMethod> methods) {
         if (interfaces == null) {
-            interfaces = ImmutableList.of();
+            interfaces = Collections.emptyList();
         } else {
-            Set<String> interfaces_copy = Sets.newHashSet(interfaces);
+            Set<String> interfaces_copy = new HashSet<>(interfaces);
             Iterator<String> interfaceIterator = interfaces.iterator();
             while (interfaceIterator.hasNext()) {
                 String iface = interfaceIterator.next();
@@ -173,13 +175,18 @@
             }
         }
 
-        ImmutableSortedSet<BuilderField> staticFields = null;
-        ImmutableSortedSet<BuilderField> instanceFields = null;
+        SortedSet<BuilderField> staticFields = null;
+        SortedSet<BuilderField> instanceFields = null;
         BuilderArrayEncodedValue internedStaticInitializers = null;
         if (fields != null) {
-            staticFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_STATIC));
-            instanceFields = ImmutableSortedSet.copyOf(Iterables.filter(fields, FieldUtil.FIELD_IS_INSTANCE));
-            ArrayEncodedValue staticInitializers = StaticInitializerUtil.getStaticInitializers(staticFields);
+            staticFields = ArraySortedSet.copyOf(CollectionUtils.naturalOrdering(),
+                    IteratorUtils.toList((Iterator<? extends BuilderField>) IteratorUtils
+                            .filter(fields, FieldUtil.FIELD_IS_STATIC)));
+            instanceFields = ArraySortedSet.copyOf(CollectionUtils.naturalOrdering(),
+                    IteratorUtils.toList((Iterator<? extends BuilderField>) IteratorUtils
+                            .filter(fields, FieldUtil.FIELD_IS_INSTANCE)));
+            ArrayEncodedValue staticInitializers = StaticInitializerUtil
+                    .getStaticInitializers(staticFields);
             if (staticInitializers != null) {
                 internedStaticInitializers = encodedArraySection.internArrayEncodedValue(staticInitializers);
             }
@@ -267,14 +274,10 @@
     @Nonnull private List<BuilderMethodParameter> internMethodParameters(
             @Nullable List<? extends MethodParameter> methodParameters) {
         if (methodParameters == null) {
-            return ImmutableList.of();
+            return Collections.emptyList();
         }
-        return ImmutableList.copyOf(Iterators.transform(methodParameters.iterator(),
-                new Function<MethodParameter, BuilderMethodParameter>() {
-                    @Nullable @Override public BuilderMethodParameter apply(MethodParameter input) {
-                        return internMethodParameter(input);
-                    }
-                }));
+        return Collections.unmodifiableList(methodParameters.stream().map(methodParam ->
+            internMethodParameter(methodParam)).collect(Collectors.toList()));
     }
 
     @Nonnull private BuilderMethodParameter internMethodParameter(@Nonnull MethodParameter methodParameter) {
@@ -350,14 +353,8 @@
 
     @Nonnull Set<? extends BuilderAnnotationElement> internAnnotationElements(
             @Nonnull Set<? extends AnnotationElement> elements) {
-        return ImmutableSet.copyOf(
-                Iterators.transform(elements.iterator(),
-                        new Function<AnnotationElement, BuilderAnnotationElement>() {
-                            @Nullable @Override
-                            public BuilderAnnotationElement apply(AnnotationElement input) {
-                                return internAnnotationElement(input);
-                            }
-                        }));
+        return Collections.unmodifiableSet(elements.stream().map(annotationElement ->
+            internAnnotationElement(annotationElement)).collect(Collectors.toSet()));
     }
 
     @Nonnull private BuilderAnnotationElement internAnnotationElement(@Nonnull AnnotationElement annotationElement) {
@@ -423,14 +420,8 @@
     }
 
     @Nonnull private BuilderArrayEncodedValue internArrayEncodedValue(@Nonnull ArrayEncodedValue value) {
-        return new BuilderArrayEncodedValue(
-                ImmutableList.copyOf(
-                        Iterators.transform(value.getValue().iterator(),
-                                new Function<EncodedValue, BuilderEncodedValue>() {
-                                    @Nullable @Override public BuilderEncodedValue apply(EncodedValue input) {
-                                        return internEncodedValue(input);
-                                    }
-                                })));
+        return new BuilderArrayEncodedValue(Collections.unmodifiableList(value.getValue().stream()
+            .map(encodedVal -> internEncodedValue(encodedVal)).collect(Collectors.toList())));
     }
 
     @Nonnull private BuilderEnumEncodedValue internEnumEncodedValue(@Nonnull EnumEncodedValue value) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/io/FileDeferredOutputStream.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/io/FileDeferredOutputStream.java
index c425e29..a89af84 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/io/FileDeferredOutputStream.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/io/FileDeferredOutputStream.java
@@ -30,7 +30,7 @@
 
 package com.android.tools.smali.dexlib2.writer.io;
 
-import com.google.common.io.ByteStreams;
+import com.android.tools.smali.util.InputStreamUtil;
 
 import java.io.BufferedOutputStream;
 import java.io.File;
@@ -71,7 +71,7 @@
         // did we actually write something out to disk?
         if (count != writtenBytes) {
             InputStream fis = new FileInputStream(backingFile);
-            ByteStreams.copy(fis, dest);
+            InputStreamUtil.copy(fis, dest);
             backingFile.delete();
         }
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/io/MemoryDeferredOutputStream.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/io/MemoryDeferredOutputStream.java
index e981100..d4392fa 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/io/MemoryDeferredOutputStream.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/io/MemoryDeferredOutputStream.java
@@ -30,11 +30,10 @@
 
 package com.android.tools.smali.dexlib2.writer.io;
 
-import com.google.common.collect.Lists;
-
 import javax.annotation.Nonnull;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -43,7 +42,7 @@
 public class MemoryDeferredOutputStream extends DeferredOutputStream {
     private static final int DEFAULT_BUFFER_SIZE = 16 * 1024;
 
-    private final List<byte[]> buffers = Lists.newArrayList();
+    private final List<byte[]> buffers = new ArrayList<>();
     private byte[] currentBuffer;
     private int currentPosition;
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/BasePool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/BasePool.java
index 63c12f2..c81f9a2 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/BasePool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/BasePool.java
@@ -30,15 +30,14 @@
 
 package com.android.tools.smali.dexlib2.writer.pool;
 
-import com.google.common.collect.Maps;
-
 import javax.annotation.Nonnull;
 import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.Map;
 
 public class BasePool<Key, Value> implements Markable {
     @Nonnull protected final DexPool dexPool;
-    @Nonnull protected final Map<Key, Value> internedItems = Maps.newLinkedHashMap();
+    @Nonnull protected final Map<Key, Value> internedItems = new LinkedHashMap<>();
     private int markedItemCount = -1;
 
     public BasePool(@Nonnull DexPool dexPool) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/ClassPool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/ClassPool.java
index a6a6fbb..be61f1b 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/ClassPool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/ClassPool.java
@@ -59,13 +59,9 @@
 import com.android.tools.smali.dexlib2.writer.DebugWriter;
 import com.android.tools.smali.dexlib2.writer.util.StaticInitializerUtil;
 import com.android.tools.smali.util.AbstractForwardSequentialList;
+import com.android.tools.smali.util.CollectionUtils;
 import com.android.tools.smali.util.ExceptionWithContext;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Ordering;
+import com.android.tools.smali.util.TransformedIterator;
 import com.android.tools.smali.dexlib2.builder.MutableMethodImplementation;
 import com.android.tools.smali.dexlib2.formatter.DexFormatter;
 import com.android.tools.smali.dexlib2.iface.instruction.DualReferenceInstruction;
@@ -75,12 +71,16 @@
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 
 import java.util.AbstractCollection;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.function.Function;
+import java.util.function.Predicate;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.io.IOException;
@@ -235,10 +235,11 @@
         }
     }
 
-    private ImmutableList<PoolClassDef> sortedClasses = null;
+    private List<PoolClassDef> sortedClasses = null;
     @Nonnull @Override public Collection<? extends PoolClassDef> getSortedClasses() {
         if (sortedClasses == null) {
-            sortedClasses = Ordering.natural().immutableSortedCopy(internedItems.values());
+            sortedClasses = CollectionUtils.immutableSortedCopy(
+                    internedItems.values(), CollectionUtils.usingToStringOrdering());
         }
         return sortedClasses;
     }
@@ -360,7 +361,7 @@
 
     private static final Predicate<MethodParameter> HAS_PARAMETER_ANNOTATIONS = new Predicate<MethodParameter>() {
         @Override
-        public boolean apply(MethodParameter input) {
+        public boolean test(MethodParameter input) {
             return input.getAnnotations().size() > 0;
         }
     };
@@ -376,13 +377,12 @@
     @Nullable @Override public List<? extends Set<? extends Annotation>> getParameterAnnotations(
             @Nonnull final PoolMethod method) {
         final List<? extends MethodParameter> parameters = method.getParameters();
-        boolean hasParameterAnnotations = Iterables.any(parameters, HAS_PARAMETER_ANNOTATIONS);
+        boolean hasParameterAnnotations = parameters.stream().anyMatch(HAS_PARAMETER_ANNOTATIONS);
 
         if (hasParameterAnnotations) {
             return new AbstractForwardSequentialList<Set<? extends Annotation>>() {
                 @Nonnull @Override public Iterator<Set<? extends Annotation>> iterator() {
-                    return FluentIterable.from(parameters)
-                            .transform(PARAMETER_ANNOTATIONS).iterator();
+                    return new TransformedIterator<>(parameters.iterator(), PARAMETER_ANNOTATIONS);
                 }
 
                 @Override public int size() {
@@ -402,7 +402,7 @@
     }
 
     @Nullable @Override public Iterable<CharSequence> getParameterNames(@Nonnull PoolMethod method) {
-        return Iterables.transform(method.getParameters(), new Function<MethodParameter, CharSequence>() {
+        return new TransformedIterator(method.getParameters(), new Function<MethodParameter, CharSequence>() {
             @Nullable @Override public CharSequence apply(MethodParameter input) {
                 return input.getName();
             }
@@ -431,7 +431,7 @@
         if (impl != null) {
             return impl.getTryBlocks();
         }
-        return ImmutableList.of();
+        return Collections.emptyList();
     }
 
     @Nullable @Override public CharSequence getExceptionType(@Nonnull ExceptionHandler handler) {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/PoolClassDef.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/PoolClassDef.java
index 59e4a5b..fc146ec 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/PoolClassDef.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/PoolClassDef.java
@@ -30,32 +30,33 @@
 
 package com.android.tools.smali.dexlib2.writer.pool;
 
+import com.android.tools.smali.dexlib2.base.reference.BaseTypeReference;
 import com.android.tools.smali.dexlib2.iface.Annotation;
 import com.android.tools.smali.dexlib2.iface.ClassDef;
 import com.android.tools.smali.dexlib2.iface.Field;
-import com.android.tools.smali.dexlib2.base.reference.BaseTypeReference;
+import com.android.tools.smali.util.ArraySortedSet;
+import com.android.tools.smali.util.CollectionUtils;
+import com.android.tools.smali.util.IteratorUtils;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSortedSet;
-import com.google.common.collect.Iterables;
-import com.google.common.collect.Iterators;
-import com.google.common.collect.Ordering;
 import java.util.AbstractCollection;
+import java.util.ArrayList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
 import java.util.SortedSet;
+import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 
 class PoolClassDef extends BaseTypeReference implements ClassDef {
     @Nonnull final ClassDef classDef;
     @Nonnull final TypeListPool.Key<List<String>> interfaces;
-    @Nonnull final ImmutableSortedSet<Field> staticFields;
-    @Nonnull final ImmutableSortedSet<Field> instanceFields;
-    @Nonnull final ImmutableSortedSet<PoolMethod> directMethods;
-    @Nonnull final ImmutableSortedSet<PoolMethod> virtualMethods;
+    @Nonnull final SortedSet<Field> staticFields;
+    @Nonnull final SortedSet<Field> instanceFields;
+    @Nonnull final SortedSet<PoolMethod> directMethods;
+    @Nonnull final SortedSet<PoolMethod> virtualMethods;
 
     int classDefIndex = DexPool.NO_INDEX;
     int annotationDirectoryOffset = DexPool.NO_OFFSET;
@@ -63,13 +64,17 @@
     PoolClassDef(@Nonnull ClassDef classDef) {
         this.classDef = classDef;
 
-        interfaces = new TypeListPool.Key<List<String>>(ImmutableList.copyOf(classDef.getInterfaces()));
-        staticFields = ImmutableSortedSet.copyOf(classDef.getStaticFields());
-        instanceFields = ImmutableSortedSet.copyOf(classDef.getInstanceFields());
-        directMethods = ImmutableSortedSet.copyOf(
-                Iterables.transform(classDef.getDirectMethods(), PoolMethod.TRANSFORM));
-        virtualMethods = ImmutableSortedSet.copyOf(
-                Iterables.transform(classDef.getVirtualMethods(), PoolMethod.TRANSFORM));
+        interfaces = new TypeListPool.Key<List<String>>(Collections.unmodifiableList(new ArrayList<>(classDef.getInterfaces())));
+        staticFields = ArraySortedSet.copyOf(CollectionUtils.naturalOrdering(), 
+            IteratorUtils.toList(classDef.getStaticFields()));
+        instanceFields = ArraySortedSet.copyOf(CollectionUtils.naturalOrdering(), 
+            IteratorUtils.toList(classDef.getInstanceFields()));
+        directMethods = ArraySortedSet.copyOf(CollectionUtils.naturalOrdering(),
+                IteratorUtils.toList(classDef.getDirectMethods()).stream().map(PoolMethod.TRANSFORM)
+                        .collect(Collectors.toList()));
+        virtualMethods = ArraySortedSet.of(CollectionUtils.naturalOrdering(),
+                IteratorUtils.toList(classDef.getVirtualMethods()).stream().map(PoolMethod.TRANSFORM)
+                .collect(Collectors.toList()));
     }
 
     @Nonnull @Override public String getType() {
@@ -107,9 +112,10 @@
     @Nonnull @Override public Collection<Field> getFields() {
         return new AbstractCollection<Field>() {
             @Nonnull @Override public Iterator<Field> iterator() {
-                return Iterators.mergeSorted(
-                        ImmutableList.of(staticFields.iterator(), instanceFields.iterator()),
-                        Ordering.natural());
+                ArrayList<Field> fields = new ArrayList<>(staticFields);
+                fields.addAll(instanceFields);
+                fields.sort(CollectionUtils.naturalOrdering());
+                return fields.iterator();
             }
 
             @Override public int size() {
@@ -129,9 +135,10 @@
     @Nonnull @Override public Collection<PoolMethod> getMethods() {
         return new AbstractCollection<PoolMethod>() {
             @Nonnull @Override public Iterator<PoolMethod> iterator() {
-                return Iterators.mergeSorted(
-                        ImmutableList.of(directMethods.iterator(), virtualMethods.iterator()),
-                        Ordering.natural());
+                ArrayList<PoolMethod> methods = new ArrayList<>(directMethods);
+                methods.addAll(virtualMethods);
+                methods.sort(CollectionUtils.naturalOrdering());
+                return methods.iterator();
             }
 
             @Override public int size() {
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/PoolMethod.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/PoolMethod.java
index 7594f5e..7df8be5 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/PoolMethod.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/PoolMethod.java
@@ -35,14 +35,13 @@
 import com.android.tools.smali.dexlib2.iface.Method;
 import com.android.tools.smali.dexlib2.iface.MethodImplementation;
 import com.android.tools.smali.dexlib2.iface.MethodParameter;
-import com.google.common.base.Function;
 import com.android.tools.smali.dexlib2.base.reference.BaseMethodReference;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.List;
 import java.util.Set;
-
+import java.util.function.Function;
 
 class PoolMethod extends BaseMethodReference implements Method {
     @Nonnull private final Method method;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/TypeListPool.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/TypeListPool.java
index 98e77c0..b36df14 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/TypeListPool.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/pool/TypeListPool.java
@@ -32,12 +32,12 @@
 
 import com.android.tools.smali.dexlib2.writer.DexWriter;
 import com.android.tools.smali.dexlib2.writer.TypeListSection;
-import com.google.common.collect.ImmutableList;
 import com.android.tools.smali.dexlib2.writer.pool.TypeListPool.Key;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.Iterator;
 
 public class TypeListPool extends BaseNullableOffsetPool<Key<? extends Collection<? extends CharSequence>>>
@@ -64,7 +64,7 @@
     @Nonnull @Override
     public Collection<? extends CharSequence> getTypes(Key<? extends Collection<? extends CharSequence>> typesKey) {
         if (typesKey == null) {
-            return ImmutableList.of();
+            return Collections.emptyList();
         }
         return typesKey.types;
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/util/CallSiteUtil.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/util/CallSiteUtil.java
index b17eddb..53473a3 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/util/CallSiteUtil.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/util/CallSiteUtil.java
@@ -31,7 +31,6 @@
 package com.android.tools.smali.dexlib2.writer.util;
 
 import com.android.tools.smali.dexlib2.immutable.value.ImmutableStringEncodedValue;
-import com.google.common.collect.Lists;
 import com.android.tools.smali.dexlib2.base.value.BaseArrayEncodedValue;
 import com.android.tools.smali.dexlib2.base.value.BaseMethodHandleEncodedValue;
 import com.android.tools.smali.dexlib2.base.value.BaseMethodTypeEncodedValue;
@@ -42,6 +41,7 @@
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 
 import javax.annotation.Nonnull;
+import java.util.ArrayList;
 import java.util.List;
 
 public class CallSiteUtil {
@@ -50,7 +50,7 @@
             @Nonnull
             @Override
             public List<? extends EncodedValue> getValue() {
-                List<EncodedValue> encodedCallSite = Lists.newArrayList();
+                List<EncodedValue> encodedCallSite = new ArrayList<>();
 
                 encodedCallSite.add(new BaseMethodHandleEncodedValue() {
                     @Nonnull
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/util/StaticInitializerUtil.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/util/StaticInitializerUtil.java
index 1974c95..11c9a01 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/util/StaticInitializerUtil.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/util/StaticInitializerUtil.java
@@ -35,15 +35,15 @@
 import com.android.tools.smali.dexlib2.util.EncodedValueUtils;
 import com.android.tools.smali.util.AbstractForwardSequentialList;
 import com.android.tools.smali.util.CollectionUtils;
-import com.google.common.base.Function;
-import com.google.common.base.Predicate;
-import com.google.common.collect.FluentIterable;
 import com.android.tools.smali.dexlib2.base.value.BaseArrayEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.ArrayEncodedValue;
 import com.android.tools.smali.dexlib2.iface.value.EncodedValue;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
 import java.util.Iterator;
 import java.util.List;
 import java.util.SortedSet;
@@ -60,9 +60,8 @@
                 public List<? extends EncodedValue> getValue() {
                     return new AbstractForwardSequentialList<EncodedValue>() {
                         @Nonnull @Override public Iterator<EncodedValue> iterator() {
-                            return FluentIterable.from(sortedStaticFields)
-                                    .limit(lastIndex+1)
-                                    .transform(GET_INITIAL_VALUE).iterator();
+                            return sortedStaticFields.stream().limit(lastIndex + 1)
+                                .map(GET_INITIAL_VALUE).collect(Collectors.toList()).iterator();
                         }
 
                         @Override public int size() {
@@ -77,7 +76,7 @@
 
     private static final Predicate<Field> HAS_INITIALIZER = new Predicate<Field>() {
         @Override
-        public boolean apply(Field input) {
+        public boolean test(Field input) {
             EncodedValue encodedValue = input.getInitialValue();
             return encodedValue != null && !EncodedValueUtils.isDefaultValue(encodedValue);
         }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/util/TryListBuilder.java b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/util/TryListBuilder.java
index 4670d16..152bbff 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/util/TryListBuilder.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/dexlib2/writer/util/TryListBuilder.java
@@ -34,10 +34,11 @@
 import com.android.tools.smali.dexlib2.iface.ExceptionHandler;
 import com.android.tools.smali.dexlib2.iface.TryBlock;
 import com.android.tools.smali.util.ExceptionWithContext;
-import com.google.common.collect.Lists;
+import com.android.tools.smali.util.IteratorUtils;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 import java.util.NoSuchElementException;
@@ -101,7 +102,7 @@
 
         public int startCodeAddress;
         public int endCodeAddress;
-        @Nonnull public List<EH> exceptionHandlers = Lists.newArrayList();
+        @Nonnull public List<EH> exceptionHandlers = new ArrayList<>();
 
         public MutableTryBlock(int startCodeAddress, int endCodeAddress) {
             this.startCodeAddress = startCodeAddress;
@@ -112,7 +113,7 @@
                                @Nonnull List<EH> exceptionHandlers) {
             this.startCodeAddress = startCodeAddress;
             this.endCodeAddress = endCodeAddress;
-            this.exceptionHandlers = Lists.newArrayList(exceptionHandlers);
+            this.exceptionHandlers = new ArrayList<>(exceptionHandlers);
         }
 
         @Override public int getStartCodeAddress() {
@@ -312,7 +313,7 @@
     }
 
     public List<TryBlock<EH>> getTryBlocks() {
-        return Lists.newArrayList(new Iterator<TryBlock<EH>>() {
+        return IteratorUtils.toList(new Iterator<TryBlock<EH>>() {
             // The next TryBlock to return. This has already been merged, if needed.
             @Nullable private MutableTryBlock<EH> next;
 
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/AbstractIterator.java b/dexlib2/src/main/java/com/android/tools/smali/util/AbstractIterator.java
new file mode 100644
index 0000000..907a863
--- /dev/null
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/AbstractIterator.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2024, Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.tools.smali.util;
+
+import javax.annotation.Nullable;
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+public abstract class AbstractIterator<T> implements Iterator<T>, Iterable<T> {
+    /** We have computed the next element and haven't returned it yet. */
+    private static final int STATE_READY = 1;
+
+    /** We haven't yet computed or have already returned the element. */
+    private static final int STATE_NOT_READY = 2;
+
+    /** We have reached the end of the data and are finished. */
+    private static final int STATE_DONE = 3;
+
+    /** We've suffered an exception and are kaputt. */
+    private static final int STATE_FAILED = 4;
+
+    private int state = STATE_NOT_READY;
+    private T next;
+
+    protected final T endOfData() {
+        state = STATE_DONE;
+        return null;
+    }
+
+    @Override
+    public final boolean hasNext() {
+        switch (state) {
+            case STATE_DONE:
+                return false;
+            case STATE_READY:
+                return true;
+            case STATE_FAILED:
+                throw new IllegalStateException();
+            default:
+        }
+        return tryToComputeNext();
+    }
+
+    private boolean tryToComputeNext() {
+        state = STATE_FAILED; // temporary pessimism
+        next = computeNext();
+        if (state != STATE_DONE) {
+            state = STATE_READY;
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    public final T next() {
+        if (!hasNext()) {
+            throw new NoSuchElementException();
+        }
+        state = STATE_NOT_READY;
+        T result = next;
+        next = null;
+        return result;
+    }
+
+    @Override
+    public final Iterator<T> iterator() {
+        return this;
+    }
+
+    /**
+     * Computes next item for the iterator. If the end of the list has been reached, it should call
+     * endOfData. endOfData has a return value of T, so you can simply {@code return endOfData()}
+     *
+     * @return The item that was read. If endOfData was called, the return value is ignored.
+     */
+
+    @Nullable
+    protected abstract T computeNext();
+}
+
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/ArraySortedSet.java b/dexlib2/src/main/java/com/android/tools/smali/util/ArraySortedSet.java
index 46c90b6..7bc1613 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/ArraySortedSet.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/ArraySortedSet.java
@@ -30,31 +30,56 @@
 
 package com.android.tools.smali.util;
 
-import com.google.common.collect.Iterators;
-
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.NoSuchElementException;
 import java.util.Set;
 import java.util.SortedSet;
+import java.util.stream.Collectors;
 import javax.annotation.Nonnull;
 
+/* A sorted set implemented with an underlying array. ArraySortedSet is inmutable. */
 public class ArraySortedSet<T> implements SortedSet<T> {
     @Nonnull private final Comparator<? super T> comparator;
     @Nonnull private final Object[] arr;
 
     private ArraySortedSet(@Nonnull Comparator<? super T> comparator, @Nonnull T[] arr) {
-        // we assume arr is already sorted by comparator, and all entries are unique
         this.comparator = comparator;
         this.arr = arr;
+        assert assertSorted();
+    }
+
+    private ArraySortedSet(@Nonnull Comparator<? super T> comparator, @Nonnull Collection<? extends T> collection) {
+        this.comparator = comparator;
+        this.arr = collection.toArray();
+        assert assertSorted();
     }
 
     public static <T> ArraySortedSet<T> of(@Nonnull Comparator<? super T> comparator, @Nonnull T[] arr) {
         return new ArraySortedSet<T>(comparator, arr);
     }
 
+    public static <T> ArraySortedSet<T> of(@Nonnull Comparator<? super T> comparator, @Nonnull Collection<? extends T> collection) {
+        return new ArraySortedSet<T>(comparator, collection);
+    }
+
+    /* Copies without duplicates and sorts the given collection to create an ArraySortedSet from it */
+    public static <T> ArraySortedSet<T> copyOf(@Nonnull Comparator<? super T> comparator, @Nonnull Collection<? extends T> collection) {
+        List<T> tmp = (List<T>)collection.stream().distinct().sorted(comparator).collect(Collectors.toList());
+        return new ArraySortedSet<T>(comparator, (T[])tmp.toArray());
+    }
+
+    private boolean assertSorted() {
+        for (int i = 1; i < arr.length; i++) {
+          assert comparator.compare((T)arr[i - 1], (T)arr[i]) < 0;
+        }
+        return true;
+    }
+
     @Override
     public int size() {
         return arr.length;
@@ -74,7 +99,7 @@
     @Override
     @SuppressWarnings("unchecked")
     public Iterator<T> iterator() {
-        return Iterators.forArray((T[])arr);
+        return Arrays.asList((T[])arr).iterator();
     }
 
     @Override
@@ -189,7 +214,7 @@
             if (arr.length != other.size()) {
                 return false;
             }
-            return Iterators.elementsEqual(iterator(), other.iterator());
+            return IteratorUtils.elementsEqual(iterator(), other.iterator());
         }
         if (o instanceof Set) {
             Set other = (Set)o;
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/ChainedIterator.java b/dexlib2/src/main/java/com/android/tools/smali/util/ChainedIterator.java
index ed8eab1..3c34247 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/ChainedIterator.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/ChainedIterator.java
@@ -32,7 +32,6 @@
 
 import java.lang.Iterable;
 import java.util.Iterator;
-import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * Combines two iterators into a single iterator. The returned iterator iterates across the elements
@@ -41,7 +40,7 @@
  * <p>
  * The returned iterator does not support {@code remove()}.
  */
-public class ChainedIterator<T extends @Nullable Object> implements Iterator<T>, Iterable<T> {
+public class ChainedIterator<T extends Object> implements Iterator<T>, Iterable<T> {
     Iterator<T> iteratorA;
     Iterator<T> iteratorB;
 
@@ -50,6 +49,11 @@
         this.iteratorB = iterableB.iterator();
     }
 
+    public ChainedIterator(Iterator<T> iteratorA, Iterator<T> iteratorB) {
+        this.iteratorA = iteratorA;
+        this.iteratorB = iteratorB;
+    }
+
     @Override
     public final boolean hasNext() {
         return iteratorA.hasNext() || iteratorB.hasNext();
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/CharSequenceUtils.java b/dexlib2/src/main/java/com/android/tools/smali/util/CharSequenceUtils.java
index 587cf2a..f7b08e3 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/CharSequenceUtils.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/CharSequenceUtils.java
@@ -30,21 +30,25 @@
 
 package com.android.tools.smali.util;
 
-import com.google.common.base.Function;
-import com.google.common.base.Functions;
-import com.google.common.collect.Lists;
+import java.util.function.Function;
+import java.util.Iterator;
 
 import java.util.List;
 
 public class CharSequenceUtils {
-    private static final Function<Object, String> TO_STRING = Functions.toStringFunction();
+    private static final Function<Object, String> TO_STRING = new Function<Object,String>() {
+        @Override
+        public String apply(Object o) {
+            return o.toString();
+        }
+    };
 
     public static int listHashCode(List<? extends CharSequence> list) {
-        return Lists.transform(list, TO_STRING).hashCode();
+        return IteratorUtils.toList((Iterator)new TransformedIterator(list.iterator(), TO_STRING)).hashCode();
     }
 
     public static boolean listEquals(List<? extends CharSequence> list1, List<? extends CharSequence> list2) {
-        return Lists.transform(list1, TO_STRING).equals(
-                Lists.transform(list2, TO_STRING));
+        return IteratorUtils.toList((Iterator)new TransformedIterator(list1.iterator(), TO_STRING)).equals(
+                IteratorUtils.toList((Iterator)new TransformedIterator(list2.iterator(), TO_STRING)));
     }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/CollectionUtils.java b/dexlib2/src/main/java/com/android/tools/smali/util/CollectionUtils.java
index 2fe222a..7883dcf 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/CollectionUtils.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/CollectionUtils.java
@@ -30,14 +30,16 @@
 
 package com.android.tools.smali.util;
 
-import com.google.common.base.Predicate;
-import com.google.common.collect.ImmutableSortedSet;
+import com.android.tools.smali.util.ArraySortedSet;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Iterator;
+import java.util.List;
 import java.util.SortedSet;
+import java.util.function.Predicate;
 
 import javax.annotation.Nonnull;
 
@@ -54,7 +56,7 @@
         int index = 0;
         int lastMatchingIndex = -1;
         for (T item: iterable) {
-            if (predicate.apply(item)) {
+            if (predicate.test(item)) {
                 lastMatchingIndex = index;
             }
             index++;
@@ -177,7 +179,7 @@
             }
         }
 
-        return ImmutableSortedSet.copyOf(elementComparator, collection);
+        return Collections.unmodifiableSortedSet(ArraySortedSet.of(elementComparator, collection));
     }
 
     @Nonnull
@@ -224,6 +226,13 @@
         return 0;
     }
 
+    public static <T> List<T> immutableSortedCopy(
+            @Nonnull Collection<T> collection, @Nonnull Comparator<? super T> comparator) {
+        ArrayList<T> copy = new ArrayList<>(collection);
+        copy.sort(comparator);
+        return Collections.unmodifiableList(copy);
+    }
+
     public static <T> Comparator<? super T> usingToStringOrdering() {
         return UsingToStringOrdering.INSTANCE;
     }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/ImmutableConverter.java b/dexlib2/src/main/java/com/android/tools/smali/util/ImmutableConverter.java
index a526c74..5d48d70 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/ImmutableConverter.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/ImmutableConverter.java
@@ -30,28 +30,34 @@
 
 package com.android.tools.smali.util;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
+import static java.util.Collections.unmodifiableList;
+import static java.util.Collections.unmodifiableSet;
+import static java.util.Collections.unmodifiableSortedSet;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.ArrayList;
+import java.util.Collections;
 import java.util.Comparator;
+import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
 import java.util.SortedSet;
+import java.util.TreeSet;
 
 public abstract class ImmutableConverter<ImmutableItem, Item> {
     protected abstract boolean isImmutable(@Nonnull Item item);
     @Nonnull protected abstract ImmutableItem makeImmutable(@Nonnull Item item);
 
     @Nonnull
-    public ImmutableList<ImmutableItem> toList(@Nullable final Iterable<? extends Item> iterable) {
+    public List<ImmutableItem> toList(@Nullable final Iterable<? extends Item> iterable) {
         if (iterable == null) {
-            return ImmutableList.of();
+            return Collections.emptyList();
         }
 
         boolean needsCopy = false;
-        if (iterable instanceof ImmutableList) {
+        if (iterable instanceof List) {
             for (Item element: iterable) {
                 if (!isImmutable(element)) {
                     needsCopy = true;
@@ -63,26 +69,27 @@
         }
 
         if (!needsCopy) {
-            return (ImmutableList<ImmutableItem>)iterable;
+            return unmodifiableList((List<ImmutableItem>)iterable);
         }
 
         final Iterator<? extends Item> iter = iterable.iterator();
 
-        return ImmutableList.copyOf(new Iterator<ImmutableItem>() {
-            @Override public boolean hasNext() { return iter.hasNext(); }
-            @Override public ImmutableItem next() { return makeImmutable(iter.next()); }
-            @Override public void remove() { iter.remove(); }
-        });
+        ArrayList<ImmutableItem> list = new ArrayList<ImmutableItem>();
+        while (iter.hasNext()) {
+            list.add(makeImmutable(iter.next()));
+        }
+
+        return unmodifiableList(list);
     }
 
     @Nonnull
-    public ImmutableSet<ImmutableItem> toSet(@Nullable final Iterable<? extends Item> iterable) {
+    public Set<ImmutableItem> toSet(@Nullable final Iterable<? extends Item> iterable) {
         if (iterable == null) {
-            return ImmutableSet.of();
+            return Collections.emptySet();
         }
 
         boolean needsCopy = false;
-        if (iterable instanceof ImmutableSet) {
+        if (iterable instanceof Set) {
             for (Item element: iterable) {
                 if (!isImmutable(element)) {
                     needsCopy = true;
@@ -94,66 +101,48 @@
         }
 
         if (!needsCopy) {
-            return (ImmutableSet<ImmutableItem>)iterable;
+            return unmodifiableSet((Set<ImmutableItem>)iterable);
         }
 
         final Iterator<? extends Item> iter = iterable.iterator();
 
-        return ImmutableSet.copyOf(new Iterator<ImmutableItem>() {
-            @Override public boolean hasNext() { return iter.hasNext(); }
-            @Override public ImmutableItem next() { return makeImmutable(iter.next()); }
-            @Override public void remove() { iter.remove(); }
-        });
-    }
-
-    @Nonnull
-    public ImmutableSortedSet<ImmutableItem> toSortedSet(@Nonnull Comparator<? super ImmutableItem> comparator,
-                                                         @Nullable final Iterable<? extends Item> iterable) {
-        if (iterable == null) {
-            return ImmutableSortedSet.of();
+        HashSet<ImmutableItem> set = new HashSet<ImmutableItem>();
+        while (iter.hasNext()) {
+            set.add(makeImmutable(iter.next()));
         }
-
-        boolean needsCopy = false;
-        if (iterable instanceof ImmutableSortedSet &&
-                ((ImmutableSortedSet)iterable).comparator().equals(comparator)) {
-            for (Item element: iterable) {
-                if (!isImmutable(element)) {
-                    needsCopy = true;
-                    break;
-                }
-            }
-        } else {
-            needsCopy = true;
-        }
-
-        if (!needsCopy) {
-            return (ImmutableSortedSet<ImmutableItem>)iterable;
-        }
-
-        final Iterator<? extends Item> iter = iterable.iterator();
-
-
-        return ImmutableSortedSet.copyOf(comparator, new Iterator<ImmutableItem>() {
-            @Override public boolean hasNext() { return iter.hasNext(); }
-            @Override public ImmutableItem next() { return makeImmutable(iter.next()); }
-            @Override public void remove() { iter.remove(); }
-        });
+        return unmodifiableSet(set);
     }
 
     @Nonnull
     public SortedSet<ImmutableItem> toSortedSet(@Nonnull Comparator<? super ImmutableItem> comparator,
-                                                @Nullable final SortedSet<? extends Item> sortedSet) {
-        if (sortedSet == null || sortedSet.size() == 0) {
-            return ImmutableSortedSet.of();
+                                                         @Nullable final Iterable<? extends Item> iterable) {
+        if (iterable == null) {
+            return Collections.emptySortedSet();
         }
 
-        @SuppressWarnings("unchecked")
-        ImmutableItem[] newItems = (ImmutableItem[])new Object[sortedSet.size()];
-        int index = 0;
-        for (Item item: sortedSet) {
-            newItems[index++] = makeImmutable(item);
+        boolean needsCopy = false;
+        if (iterable instanceof SortedSet &&
+                ((SortedSet)iterable).comparator().equals(comparator)) {
+            for (Item element: iterable) {
+                if (!isImmutable(element)) {
+                    needsCopy = true;
+                    break;
+                }
+            }
+        } else {
+            needsCopy = true;
         }
 
-        return ArraySortedSet.of(comparator, newItems);
+        if (!needsCopy) {
+            return unmodifiableSortedSet((SortedSet<ImmutableItem>)iterable);
+        }
+
+        final Iterator<? extends Item> iter = iterable.iterator();
+
+        TreeSet<ImmutableItem> treeSet = new TreeSet<ImmutableItem>(comparator);
+        while (iter.hasNext()) {
+            treeSet.add(makeImmutable(iter.next()));
+        }
+        return unmodifiableSortedSet(treeSet);
     }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/ImmutableUtils.java b/dexlib2/src/main/java/com/android/tools/smali/util/ImmutableUtils.java
index fbd67e3..0107f85 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/ImmutableUtils.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/ImmutableUtils.java
@@ -30,32 +30,36 @@
 
 package com.android.tools.smali.util;
 
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.ImmutableSortedSet;
+import static java.util.Collections.unmodifiableSet;
+import static java.util.Collections.unmodifiableSortedSet;
+import static java.util.Collections.unmodifiableList;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Set;
+import java.util.SortedSet;
 
 public class ImmutableUtils {
-    @Nonnull public static <T> ImmutableList<T> nullToEmptyList(@Nullable ImmutableList<T> list) {
+    @Nonnull public static <T> List<T> nullToEmptyList(@Nullable List<T> list) {
         if (list == null) {
-            return ImmutableList.of();
+            return Collections.emptyList();
         }
-        return list;
+        return unmodifiableList(list);
     }
 
-    @Nonnull public static <T> ImmutableSet<T> nullToEmptySet(@Nullable ImmutableSet<T> set) {
+    @Nonnull public static <T> Set<T> nullToEmptySet(@Nullable Set<T> set) {
         if (set == null) {
-            return ImmutableSet.of();
+            return Collections.emptySet();
         }
-        return set;
+        return unmodifiableSet(set);
     }
 
-    @Nonnull public static <T> ImmutableSortedSet<T> nullToEmptySortedSet(@Nullable ImmutableSortedSet<T> set) {
+    @Nonnull public static <T> SortedSet<T> nullToEmptySortedSet(@Nullable SortedSet<T> set) {
         if (set == null) {
-            return ImmutableSortedSet.of();
+            return Collections.emptySortedSet();
         }
-        return set;
+        return unmodifiableSortedSet(set);
     }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/InputStreamUtil.java b/dexlib2/src/main/java/com/android/tools/smali/util/InputStreamUtil.java
index 46f696a..0532f0c 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/InputStreamUtil.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/InputStreamUtil.java
@@ -38,6 +38,7 @@
 import java.io.EOFException;
 import java.io.IOException;
 import java.io.InputStream;
+import java.io.OutputStream;
 import java.util.ArrayDeque;
 import java.util.Arrays;
 import java.util.Queue;
@@ -259,4 +260,30 @@
         }
         return total;
     }
+
+    /**
+     * Copies all bytes from the input stream to the output stream. Does not close or flush either
+     * stream.
+     *
+     * @param from the input stream to read from
+     * @param to the output stream to write to
+     * @return the number of bytes copied
+     * @throws IOException if an I/O error occurs
+     */
+    public static long copy(InputStream from, OutputStream to) throws IOException {
+        if (from == null || to == null) {
+            throw new NullPointerException();
+        }
+        byte[] buf = new byte[BUFFER_SIZE];
+        long total = 0;
+        while (true) {
+            int r = from.read(buf);
+            if (r == -1) {
+                break;
+            }
+            to.write(buf, 0, r);
+            total += r;
+        }
+        return total;
+    }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/IteratorUtils.java b/dexlib2/src/main/java/com/android/tools/smali/util/IteratorUtils.java
index 6f6c857..4894d5a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/IteratorUtils.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/IteratorUtils.java
@@ -30,13 +30,16 @@
 
 package com.android.tools.smali.util;
 
+import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Iterator;
-
-import org.checkerframework.checker.nullness.qual.Nullable;
+import java.util.List;
+import java.util.Objects;
+import java.util.function.Predicate;
 
 public final class IteratorUtils {
 
-    public static <T extends @Nullable Object> T getLast(Iterator<T> iterator) {
+    public static <T extends Object> T getLast(Iterator<T> iterator) {
         while (true) {
             T current = iterator.next();
             if (!iterator.hasNext()) {
@@ -44,4 +47,67 @@
             }
         }
     }
+
+    public static <T extends Object> AbstractIterator<T> filter(
+            Iterable<T> unfiltered, Predicate<? super T> retainIfTrue) {
+        return filter(unfiltered.iterator(), retainIfTrue);
+    }
+
+    public static <T extends Object> AbstractIterator<T> filter(
+            Iterator<T> unfiltered, Predicate<? super T> retainIfTrue) {
+        return new AbstractIterator<T>() {
+            @Override
+            protected T computeNext() {
+                while (unfiltered.hasNext()) {
+                    T next = unfiltered.next();
+                    if (retainIfTrue.test(next)) {
+                        return next;
+                    }
+                }
+                return endOfData();
+            }
+        };
+    }
+
+    public static <T extends Object> List<T> toList(Iterable<T> iterable) {
+        return toList(iterable.iterator());
+    }
+
+    public static <T extends Object> List<T> toList(Iterator<T> iterator) {
+        ArrayList<T> list = new ArrayList<T>();
+        while (iterator.hasNext()) {
+            list.add(iterator.next());
+        }
+        return list;
+    }
+
+    public static <T extends Object> void addAll(Collection<T> collection, Iterator<T> iterator) {
+        while (iterator.hasNext()) {
+            collection.add(iterator.next());
+        }
+    }
+
+    public static boolean elementsEqual(Iterator<?> iterator1, Iterator<?> iterator2) {
+        while (iterator1.hasNext()) {
+            if (!iterator2.hasNext()) {
+                return false;
+            }
+            Object o1 = iterator1.next();
+            Object o2 = iterator2.next();
+            if (!Objects.equals(o1, o2)) {
+                return false;
+            }
+        }
+        return !iterator2.hasNext();
+    }
+
+    public static int size(Iterable<?> iterable) {
+        Iterator<?> iterator = iterable.iterator();
+        int count = 0;
+        while (iterator.hasNext()) {
+            count++;
+            iterator.next();
+        }
+        return count;
+    }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/Range.java b/dexlib2/src/main/java/com/android/tools/smali/util/Range.java
new file mode 100644
index 0000000..f74377f
--- /dev/null
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/Range.java
@@ -0,0 +1,297 @@
+/*
+ * Copyright 2024, Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.tools.smali.util;
+
+import java.util.Comparator;
+import java.util.Objects;
+
+/*
+ * Represents a Range of values of type C. It can have open bounds if the range doesn't include the
+ * bound value. It can also be unbounded on the lower or upper side. Simplified version of a guava
+ * Range.
+ */
+public class Range<C extends Comparable> {
+    public static final Comparator<Range<?>> RANGE_LEX_COMPARATOR = new Comparator<Range<?>>() {
+        @Override
+        public int compare(Range<?> left, Range<?> right) {
+            int cmp = 0;
+            if (!left.hasLowerBound() && right.hasLowerBound()) {
+                return -1;
+            } else if (!right.hasLowerBound() && left.hasLowerBound()) {
+                return 1;
+            } else if (left.hasLowerBound() && right.hasLowerBound()) {
+                cmp = left.lowerBound.compareTo(right.lowerBound);
+            }
+
+            if (cmp != 0) {
+                return cmp;
+            }
+            if (!left.hasUpperBound() && right.hasUpperBound()) {
+                return 1;
+            } else if (!right.hasUpperBound() && left.hasUpperBound()) {
+                return -1;
+            } else if (left.hasUpperBound() && right.hasUpperBound()) {
+                cmp = left.upperBound.compareTo(right.upperBound);
+            }
+            return cmp;
+        }
+    };
+
+    private C lowerBound;
+    private C upperBound;
+    private boolean lowerOpen;
+    private boolean upperOpen;
+    private boolean allValues;
+
+    public static <C extends Comparable> Range<C> closed(C lowerBound, C upperBound) {
+        if (lowerBound == null || upperBound == null) {
+            throw new NullPointerException();
+        }
+        if (lowerBound.compareTo(upperBound) > 0) {
+            throw new IllegalArgumentException("lowerBound must be <= upperBound");
+        }
+        return new Range<>(lowerBound, upperBound, false, false);
+    }
+
+    public static <C extends Comparable> Range<C> open(C lowerBound, C upperBound) {
+        if (lowerBound == null || upperBound == null) {
+            throw new NullPointerException();
+        }
+        if (lowerBound.compareTo(upperBound) > 0) {
+            throw new IllegalArgumentException("lowerBound must be <= upperBound");
+        }
+        return new Range<>(lowerBound, upperBound, true, true);
+    }
+
+    public static <C extends Comparable> Range<C> openClosed(C lowerBound, C upperBound) {
+        if (lowerBound == null || upperBound == null) {
+            throw new NullPointerException();
+        }
+        if (lowerBound.compareTo(upperBound) > 0) {
+            throw new IllegalArgumentException("lowerBound must be <= upperBound");
+        }
+        return new Range<>(lowerBound, upperBound, true, false);
+    }
+
+    public static <C extends Comparable> Range<C> closedOpen(C lowerBound, C upperBound) {
+        if (lowerBound == null || upperBound == null) {
+            throw new NullPointerException();
+        }
+        if (lowerBound.compareTo(upperBound) > 0) {
+            throw new IllegalArgumentException("lowerBound must be <= upperBound");
+        }
+        return new Range<>(lowerBound, upperBound, false, true);
+    }
+
+    public static <C extends Comparable> Range<C> atLeast(C lowerBound) {
+        if (lowerBound == null) {
+            throw new NullPointerException();
+        }
+        return new Range<>(lowerBound, null, false, false);
+    }
+
+    public static <C extends Comparable> Range<C> atMost(C upperBound) {
+        if (upperBound == null) {
+            throw new NullPointerException();
+        }
+        return new Range<>(null, upperBound, false, false);
+    }
+
+    public static <C extends Comparable> Range<C> allValues() {
+        return new Range<>();
+    }
+
+    private Range(C lowerBound, C upperBound, boolean lowerOpen, boolean upperOpen) {
+        this.lowerBound = lowerBound;
+        this.upperBound = upperBound;
+        this.lowerOpen = lowerOpen;
+        this.upperOpen = upperOpen;
+        allValues = false;
+    }
+
+    private Range() {
+        allValues = true;
+        lowerBound = null;
+        upperBound = null;
+        lowerOpen = false;
+        upperOpen = false;
+    }
+
+    public boolean isEmpty() {
+        return !allValues
+                && Objects.equals(lowerBound, upperBound)
+                && (lowerOpen || upperOpen);
+    }
+
+    public C getLowerBound() {
+        return lowerBound;
+    }
+
+    public C getUpperBound() {
+        return upperBound;
+    }
+
+    public boolean openLowerBound() {
+        return lowerOpen;
+    }
+
+    public boolean openUpperBound() {
+        return upperOpen;
+    }
+
+    public boolean hasAllValues() {
+        return allValues;
+    }
+
+    public boolean hasLowerBound() {
+        return lowerBound != null;
+    }
+
+    public boolean hasUpperBound() {
+        return upperBound != null;
+    }
+
+    /* Returns true if value is included in the Range */
+    public boolean contains(C value) {
+        if (value == null) {
+            return false;
+        }
+        if (allValues) {
+            return true;
+        }
+
+        if (lowerBound != null) {
+            if (lowerOpen && value.compareTo(lowerBound) == 0) {
+                return false;
+            }
+            if (value.compareTo(lowerBound) < 0) {
+                return false;
+            }
+        }
+        if (upperBound != null) {
+            if (upperOpen && value.compareTo(upperBound) == 0) {
+                return false;
+            }
+            if (value.compareTo(upperBound) > 0) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /*
+     * Returns true if there exists a (possibly empty) range which is enclosed by both this range
+     * and other.
+     */
+    public boolean isConnected(Range<C> other) {
+        return (!hasLowerBound() || !other.hasUpperBound()
+                || lowerBound.compareTo(other.getUpperBound()) <= 0)
+                && (!hasUpperBound() || !other.hasLowerBound()
+                        || other.getLowerBound().compareTo(upperBound) <= 0);
+    }
+
+    /* Returns the maximal range enclosed by both this range and other, if such a range exists. */
+    public Range<C> intersection(Range<C> other) {
+        if (!isConnected(other)) {
+            return null;
+        }
+
+        // select the max of the lowerBounds. If they're equal,
+        // choose the range that has an open lower bound
+        Range<C> lowerBoundRange;
+        if (!hasLowerBound() || !other.hasLowerBound()) {
+            lowerBoundRange = hasLowerBound() ? this : other;
+        } else if (Objects.equals(lowerBound, other.getLowerBound())) {
+            lowerBoundRange = lowerOpen ? this : other;
+        } else {
+            lowerBoundRange = lowerBound.compareTo(other.getLowerBound()) > 0 ? this : other;
+        }
+
+        // and the min of the upperBounds, or the open upper bound if they're equal
+        Range<C> upperBoundRange;
+        if (!hasUpperBound() || !other.hasUpperBound()) {
+            upperBoundRange = hasUpperBound() ? this : other;
+        } else if (Objects.equals(upperBound, other.getUpperBound())) {
+            upperBoundRange = upperOpen ? this : other;
+        } else {
+            upperBoundRange = upperBound.compareTo(other.getUpperBound()) < 0 ? this : other;
+        }
+
+        return new Range<C>(
+                lowerBoundRange.getLowerBound(),
+                upperBoundRange.getUpperBound(),
+                lowerBoundRange.openLowerBound(),
+                upperBoundRange.openUpperBound());
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == this) {
+            return true;
+        }
+        if (!(o instanceof Range)) {
+            return false;
+        }
+        Range<?> other = (Range<?>) o;
+
+        if (allValues != other.hasAllValues()) {
+            return false;
+        }
+
+        return Objects.equals(lowerBound, other.lowerBound)
+                && Objects.equals(upperBound, other.upperBound)
+                && lowerOpen == other.openLowerBound()
+                && upperOpen == other.openUpperBound();
+    }
+
+    @Override
+    public String toString() {
+        if (allValues) {
+            return "[*]";
+        }
+        String sb = "";
+        if (lowerOpen) {
+            sb += "(";
+        } else {
+            sb += "[";
+        }
+        sb += lowerBound;
+        sb += ", ";
+        sb += upperBound;
+        if (upperOpen) {
+            sb += ")";
+        } else {
+            sb += "]";
+        }
+        return sb;
+    }
+
+}
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/StringUtils.java b/dexlib2/src/main/java/com/android/tools/smali/util/StringUtils.java
index 730caa8..767c6dd 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/StringUtils.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/StringUtils.java
@@ -31,15 +31,18 @@
 package com.android.tools.smali.util;
 
 import com.android.tools.smali.dexlib2.formatter.DexFormattedWriter;
+import com.android.tools.smali.dexlib2.iface.value.CharEncodedValue;
+
 import java.io.IOException;
 import java.io.Writer;
+import java.util.Collection;
 import java.util.Iterator;
-import java.util.List;
 
 public class StringUtils {
 
     /**
-     * @deprecated Use {@link com.android.tools.smali.baksmali.formatter.BaksmaliWriter#writeCharEncodedValue}
+     * @deprecated Use @see
+     *             com.android.tools.smali.baksmali.formatter.BaksmaliWriter}#writeCharEncodedValue()
      */
     @Deprecated
     public static void writeEscapedChar(Writer writer, char c) throws IOException {
@@ -51,9 +54,15 @@
             return;
         } else if (c <= 0x7f) {
             switch (c) {
-                case '\n': writer.write("\\n"); return;
-                case '\r': writer.write("\\r"); return;
-                case '\t': writer.write("\\t"); return;
+                case '\n':
+                    writer.write("\\n");
+                    return;
+                case '\r':
+                    writer.write("\\r");
+                    return;
+                case '\t':
+                    writer.write("\\t");
+                    return;
             }
         }
 
@@ -80,9 +89,15 @@
                 continue;
             } else if (c <= 0x7f) {
                 switch (c) {
-                    case '\n': writer.write("\\n"); continue;
-                    case '\r': writer.write("\\r"); continue;
-                    case '\t': writer.write("\\t"); continue;
+                    case '\n':
+                        writer.write("\\n");
+                        continue;
+                    case '\r':
+                        writer.write("\\r");
+                        continue;
+                    case '\t':
+                        writer.write("\\t");
+                        continue;
                 }
             }
 
@@ -109,9 +124,15 @@
                 continue;
             } else if (c <= 0x7f) {
                 switch (c) {
-                    case '\n': sb.append("\\n"); continue;
-                    case '\r': sb.append("\\r"); continue;
-                    case '\t': sb.append("\\t"); continue;
+                    case '\n':
+                        sb.append("\\n");
+                        continue;
+                    case '\r':
+                        sb.append("\\r");
+                        continue;
+                    case '\t':
+                        sb.append("\\t");
+                        continue;
                 }
             }
 
@@ -125,7 +146,7 @@
         return sb.toString();
     }
 
-    public static String join(List<? extends Object> parts, String separator) {
+    public static String join(Collection<? extends Object> parts, String separator) {
         StringBuilder builder = new StringBuilder();
         Iterator<? extends Object> it = parts.iterator();
         if (it.hasNext()) {
@@ -137,4 +158,35 @@
         }
         return builder.toString();
     }
+
+    // Base on the repeat method in guava Strings, of the same signature.
+    public static String repeat(String string, int count) {
+        if (string == null) {
+            throw new NullPointerException("string == null");
+        }
+
+        if (count <= 1) {
+            if (count >= 0) {
+                throw new IllegalArgumentException("invalid count: " + count);
+            }
+            return (count == 0) ? "" : string;
+        }
+
+        final int len = string.length();
+        final long longSize = (long) len * (long) count;
+        final int size = (int) longSize;
+        if (size != longSize) {
+            throw new ArrayIndexOutOfBoundsException("Required array size too large: " + longSize);
+        }
+
+        final char[] array = new char[size];
+        string.getChars(0, len, array, 0);
+        int n;
+        for (n = len; n < size - n; n <<= 1) {
+            System.arraycopy(array, 0, array, n, n);
+        }
+        System.arraycopy(array, 0, array, n, size - n);
+        return new String(array);
+
+    }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/TransformedIterator.java b/dexlib2/src/main/java/com/android/tools/smali/util/TransformedIterator.java
index bf89ea9..ab5179a 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/TransformedIterator.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/TransformedIterator.java
@@ -32,7 +32,6 @@
 
 import java.util.Iterator;
 import java.util.function.Function;
-import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * An iterator that will return the results of applying {@code transformFunction} to each element of
@@ -40,11 +39,17 @@
  * <p>
  * The returned iterator supports {@code remove()} if {@code backingIterator} does.
  */
-public class TransformedIterator<F extends @Nullable Object, T extends @Nullable Object>
-        implements Iterator<T> {
+public class TransformedIterator<F extends Object, T extends Object>
+        implements Iterator<T>, Iterable<T> {
     final Iterator<? extends F> backingIterator;
     final Function<F, T> transformFunction;
 
+    public TransformedIterator(Iterable<? extends F> backingIterable,
+            Function<F, T> transformFunction) {
+        this.backingIterator = backingIterable.iterator();
+        this.transformFunction = transformFunction;
+    }
+
     public TransformedIterator(Iterator<? extends F> backingIterator,
             Function<F, T> transformFunction) {
         this.backingIterator = backingIterator;
@@ -65,4 +70,9 @@
     public final void remove() {
         backingIterator.remove();
     }
+
+    @Override
+    public final Iterator<T> iterator() {
+        return this;
+    }
 }
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/UnmodifiableRangeMap.java b/dexlib2/src/main/java/com/android/tools/smali/util/UnmodifiableRangeMap.java
new file mode 100644
index 0000000..eed14b6
--- /dev/null
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/UnmodifiableRangeMap.java
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2024, Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.tools.smali.util;
+
+import javax.annotation.CheckForNull;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+
+/* 
+ * Based on guava's ImmutableRangeMap
+ */
+public class UnmodifiableRangeMap<K extends Comparable<?>, V> {
+    private static final UnmodifiableRangeMap<Comparable<?>, Object> EMPTY = new UnmodifiableRangeMap<>(
+            Collections.emptyList(), Collections.emptyList());
+
+    /** Returns a new builder for an immutable range map. */
+    public static <K extends Comparable<?>, V> Builder<K, V> builder() {
+        return new Builder<>();
+    }
+
+    /**
+     * Returns an empty immutable range map.
+     * <p>
+     * <b>Performance note:</b> the instance returned is a singleton.
+     */
+    public static <K extends Comparable<?>, V> UnmodifiableRangeMap<K, V> of() {
+        return (UnmodifiableRangeMap<K, V>) EMPTY;
+    }
+
+    /**
+     * A builder for immutable range maps. Overlapping ranges are prohibited.
+     *
+     * @since 14.0
+     */
+    public static final class Builder<K extends Comparable<?>, V> {
+
+        private final List<Entry<Range<K>, V>> entries;
+
+        public Builder() {
+            this.entries = new ArrayList<>();
+        }
+
+        /**
+         * Associates the specified range with the specified value.
+         *
+         * @throws IllegalArgumentException if {@code range} is empty
+         */
+        public Builder<K, V> put(Range<K> range, V value) {
+            if (range == null || value == null) {
+                throw new NullPointerException("Both range and value must be non-null");
+            }
+
+            if (range.isEmpty()) {
+                throw new IllegalArgumentException("Ranges cannot be empty");
+            }
+            entries.add(new UnmodifiableEntry(range, value));
+            return this;
+        }
+
+        /**
+         * Returns an {@code ImmutableRangeMap} containing the associations previously added to this
+         * builder.
+         *
+         * @throws IllegalArgumentException if any two ranges inserted into this builder overlap
+         */
+        public UnmodifiableRangeMap<K, V> build() {
+            Collections.sort(entries,
+                    (e1, e2) -> Range.RANGE_LEX_COMPARATOR.compare(e1.getKey(), e2.getKey()));
+            ArrayList<Range<K>> rangesList = new ArrayList<>(entries.size());
+            ArrayList<V> valuesList = new ArrayList<>(entries.size());
+            for (int i = 0; i < entries.size(); i++) {
+                Range<K> range = entries.get(i).getKey();
+                if (i > 0) {
+                    Range<K> prevRange = entries.get(i - 1).getKey();
+                    if (range.isConnected(prevRange) && !range.intersection(prevRange).isEmpty()) {
+                        throw new IllegalArgumentException(
+                                "Overlapping ranges: range " + prevRange + " overlaps with entry "
+                                        + range);
+                    }
+                }
+                rangesList.add(range);
+                valuesList.add(entries.get(i).getValue());
+            }
+            return new UnmodifiableRangeMap(rangesList, valuesList);
+        }
+    }
+
+    private final transient List<Range<K>> ranges;
+    private final transient List<V> values;
+
+    private UnmodifiableRangeMap(List<Range<K>> ranges, List<V> values) {
+        this.ranges = Collections.unmodifiableList(ranges);
+        this.values = Collections.unmodifiableList(values);
+    }
+
+    @CheckForNull
+    public V get(K key) {
+        if (key == null) {
+            return null;
+        }
+
+        int index = rangeBinarySearch(ranges, key);
+        if (index == -1) {
+            return null;
+        } else {
+            Range<K> range = ranges.get(index);
+            return range.contains(key) ? values.get(index) : null;
+        }
+    }
+
+    @CheckForNull
+    public Entry<Range<K>, V> getEntry(K key) {
+        if (key == null) {
+            return null;
+        }
+
+        int index = rangeBinarySearch(ranges, key);
+        if (index == -1) {
+            return null;
+        } else {
+            Range<K> range = ranges.get(index);
+            return range.contains(key) ? new UnmodifiableEntry(range, values.get(index)) : null;
+        }
+    }
+
+    private static <T extends Comparable> int rangeBinarySearch(List<Range<T>> l, T key) {
+        int low = 0;
+        int high = l.size() - 1;
+
+        while (low <= high) {
+            int mid = (low + high) >>> 1;
+            Range<T> midRange = l.get(mid);
+            if (midRange.contains(key)) {
+                return mid;
+            }
+
+            int cmp = midRange.hasLowerBound() ? key.compareTo(midRange.getLowerBound())
+                    : key.compareTo(midRange.getUpperBound());
+
+            if (cmp > 0)
+                low = mid + 1;
+            else if (cmp < 0)
+                high = mid - 1;
+            else
+                return mid; // key found
+        }
+        return -1; // key not found
+    }
+
+    public static class UnmodifiableEntry<K, V> implements Map.Entry<K, V> {
+        private final K key;
+        private final V value;
+
+        public UnmodifiableEntry(K key, V value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        @Override
+        public K getKey() {
+            return key;
+        }
+
+        @Override
+        public V getValue() {
+            return value;
+        }
+
+        @Override
+        public V setValue(V value) {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
diff --git a/dexlib2/src/main/java/com/android/tools/smali/util/WrappedIndentingWriter.java b/dexlib2/src/main/java/com/android/tools/smali/util/WrappedIndentingWriter.java
index bf1798e..16873e9 100644
--- a/dexlib2/src/main/java/com/android/tools/smali/util/WrappedIndentingWriter.java
+++ b/dexlib2/src/main/java/com/android/tools/smali/util/WrappedIndentingWriter.java
@@ -30,8 +30,6 @@
 
 package com.android.tools.smali.util;
 
-import com.google.common.collect.Lists;
-
 import java.io.FilterWriter;
 import java.io.IOException;
 import java.io.Writer;
@@ -76,7 +74,8 @@
     }
 
     private void wrapLine() throws IOException {
-        List<String> wrapped = Lists.newArrayList(StringWrapper.wrapStringOnBreaks(line.toString(), maxWidth));
+        List<String> wrapped = IteratorUtils.toList(
+            StringWrapper.wrapStringOnBreaks(line.toString(), maxWidth));
         out.write(wrapped.get(0), 0, wrapped.get(0).length());
         out.write('\n');
 
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/util/RangeTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/util/RangeTest.java
new file mode 100644
index 0000000..23fea45
--- /dev/null
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/util/RangeTest.java
@@ -0,0 +1,499 @@
+
+/*
+ * Copyright 2024, Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.tools.smali.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.smali.util.Range;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class RangeTest {
+
+    @Test
+    public void testClosed() {
+        Range<Integer> range = Range.closed(1, 10);
+        assertTrue(range.contains(1));
+        assertTrue(range.contains(10));
+        assertTrue(range.contains(5));
+        assertFalse(range.contains(0));
+        assertFalse(range.contains(11));
+    }
+
+    @Test
+    public void testOpenClosed() {
+        Range<Integer> range = Range.openClosed(1, 10);
+        assertTrue(range.contains(10));
+        assertFalse(range.contains(1));
+        assertTrue(range.contains(5));
+        assertFalse(range.contains(0));
+        assertFalse(range.contains(11));
+    }
+
+    @Test
+    public void testClosedOpen() {
+        Range<Integer> range = Range.closedOpen(1, 10);
+        assertFalse(range.contains(10));
+        assertTrue(range.contains(1));
+        assertTrue(range.contains(5));
+        assertFalse(range.contains(0));
+        assertFalse(range.contains(11));
+    }
+
+    @Test
+    public void testOpen() {
+        Range<Integer> range = Range.open(1, 10);
+        assertFalse(range.contains(10));
+        assertFalse(range.contains(1));
+        assertTrue(range.contains(5));
+        assertFalse(range.contains(11));
+        assertFalse(range.contains(0));
+    }
+
+    @Test
+    public void testAtLeast() {
+        Range<Integer> range = Range.atLeast(1);
+        assertTrue(range.contains(1));
+        assertTrue(range.contains(10));
+        assertFalse(range.contains(0));
+    }
+
+    @Test
+    public void testAtMost() {
+        Range<Integer> range = Range.atMost(10);
+        assertFalse(range.contains(11));
+        assertTrue(range.contains(10));
+        assertTrue(range.contains(5));
+    }
+
+    @Test
+    public void testAllValues() {
+        Range<Integer> range = Range.allValues();
+        assertTrue(range.contains(1));
+        assertTrue(range.contains(10));
+        assertTrue(range.contains(0));
+        assertTrue(range.contains(11));
+    }
+
+    @Test
+    public void testEquals() {
+        Range<Integer> range1 = Range.closed(1, 10);
+        Range<Integer> range2 = Range.closed(1, 10);
+        assertTrue(range1.equals(range2));
+
+        range1 = Range.open(1, 10);
+        range2 = Range.open(1, 10);
+        assertTrue(range1.equals(range2));
+
+        range1 = Range.closedOpen(1, 10);
+        range2 = Range.closedOpen(1, 10);
+        assertTrue(range1.equals(range2));
+
+        range1 = Range.openClosed(1, 10);
+        range2 = Range.openClosed(1, 10);
+        assertTrue(range1.equals(range2));
+
+        range1 = Range.atLeast(1);
+        range2 = Range.atLeast(1);
+        assertTrue(range1.equals(range2));
+
+        range1 = Range.atMost(10);
+        range2 = Range.atMost(10);
+        assertTrue(range1.equals(range2));
+
+        range1 = Range.allValues();
+        range2 = Range.allValues();
+        assertTrue(range1.equals(range2));
+
+        range1 = Range.closed(1, 10);
+        range2 = Range.closed(1, 11);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.open(1, 10);
+        range2 = Range.open(0, 10);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.closed(1, 10);
+        range2 = Range.open(1, 10);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.closed(1, 10);
+        range2 = Range.closedOpen(1, 10);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.closedOpen(1, 10);
+        range2 = Range.openClosed(1, 10);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.closed(1, 10);
+        range2 = Range.atLeast(1);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.closed(1, 10);
+        range2 = Range.atMost(10);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.closed(1, 10);
+        range2 = Range.allValues();
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.open(1, 10);
+        range2 = Range.closedOpen(1, 10);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.open(1, 10);
+        range2 = Range.openClosed(1, 10);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.open(1, 10);
+        range2 = Range.atLeast(1);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.open(1, 10);
+        range2 = Range.atMost(10);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.open(1, 10);
+        range2 = Range.allValues();
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.closedOpen(1, 10);
+        range2 = Range.openClosed(1, 10);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.closedOpen(1, 10);
+        range2 = Range.atLeast(1);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.closedOpen(1, 10);
+        range2 = Range.atMost(10);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.closedOpen(1, 10);
+        range2 = Range.allValues();
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.openClosed(1, 10);
+        range2 = Range.atLeast(1);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.openClosed(1, 10);
+        range2 = Range.atMost(10);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.openClosed(1, 10);
+        range2 = Range.allValues();
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.atLeast(1);
+        range2 = Range.atMost(1);
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.atLeast(1);
+        range2 = Range.allValues();
+        assertFalse(range1.equals(range2));
+
+        range1 = Range.atMost(10);
+        range2 = Range.allValues();
+        assertFalse(range1.equals(range2));
+    }
+
+    @Test
+    public void testIsEmpty() {
+        Range<Integer> range = Range.closed(1, 1);
+        assertFalse(range.isEmpty());
+
+        range = Range.openClosed(2, 2);
+        assertTrue(range.isEmpty());
+
+        range = Range.closedOpen(3, 3);
+        assertTrue(range.isEmpty());
+
+        range = Range.open(4, 4);
+        assertTrue(range.isEmpty());
+
+        range = Range.open(4, 5);
+        assertFalse(range.isEmpty());
+
+        range = Range.atMost(10);
+        assertFalse(range.isEmpty());
+
+        range = Range.atLeast(10);
+        assertFalse(range.isEmpty());
+
+        range = Range.allValues();
+        assertFalse(range.isEmpty());
+    }
+
+    @Test
+    public void testGetLowerBound() {
+        Range<Integer> range = Range.closed(1, 10);
+        assertEquals((Integer) 1, range.getLowerBound());
+    }
+
+    @Test
+    public void testGetUpperBound() {
+        Range<Integer> range = Range.closed(1, 10);
+        assertEquals((Integer) 10, range.getUpperBound());
+    }
+
+    @Test
+    public void testHasLowerBound() {
+        assertTrue(Range.closed(1, 10).hasLowerBound());
+        assertTrue(Range.open(1, 10).hasLowerBound());
+        assertTrue(Range.openClosed(1, 10).hasLowerBound());
+        assertTrue(Range.closedOpen(1, 10).hasLowerBound());
+        assertTrue(Range.atLeast(1).hasLowerBound());
+        assertFalse(Range.atMost(10).hasLowerBound());
+        assertFalse(Range.allValues().hasLowerBound());
+    }
+
+    @Test
+    public void testHasUpperBound() {
+        assertTrue(Range.closed(1, 10).hasUpperBound());
+        assertTrue(Range.open(1, 10).hasUpperBound());
+        assertTrue(Range.openClosed(1, 10).hasUpperBound());
+        assertTrue(Range.closedOpen(1, 10).hasUpperBound());
+        assertFalse(Range.atLeast(1).hasUpperBound());
+        assertTrue(Range.atMost(10).hasUpperBound());
+        assertFalse(Range.allValues().hasUpperBound());
+    }
+
+    @Test
+    public void testIsConnected() {
+        Range<Integer> range1 = Range.closed(1, 5);
+        Range<Integer> range2 = Range.closed(3, 7);
+        assertTrue(range1.isConnected(range2));
+        assertTrue(range2.isConnected(range1));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(6, 7);
+        assertFalse(range1.isConnected(range2));
+        assertFalse(range2.isConnected(range1));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(0, 2);
+        assertTrue(range1.isConnected(range2));
+        assertTrue(range2.isConnected(range1));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(10, 20);
+        assertFalse(range1.isConnected(range2));
+        assertFalse(range2.isConnected(range1));
+    }
+
+    @Test
+    public void testIsConnected_edgeConnection() {
+        Range<Integer> range1 = Range.closed(1, 5);
+        Range<Integer> range2 = Range.closed(5, 7);
+        assertTrue(range1.isConnected(range2));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(3, 5);
+        assertTrue(range1.isConnected(range2));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(1, 3);
+        assertTrue(range1.isConnected(range2));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(1, 5);
+        assertTrue(range1.isConnected(range2));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(5, 5);
+        assertTrue(range1.isConnected(range2));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.openClosed(5, 10);
+        assertTrue(range1.isConnected(range2));
+    }
+
+    @Test
+    public void testIntersection() {
+        Range<Integer> range1 = Range.closed(1, 5);
+        Range<Integer> range2 = Range.closed(3, 7);
+        assertEquals(Range.closed(3, 5), range1.intersection(range2));
+        assertEquals(Range.closed(3, 5), range2.intersection(range1));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(6, 7);
+        assertNull(range1.intersection(range2));
+        assertNull(range2.intersection(range1));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(0, 2);
+        assertEquals(Range.closed(1, 2), range1.intersection(range2));
+        assertEquals(Range.closed(1, 2), range2.intersection(range1));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(5, 7);
+        assertEquals(Range.closed(5, 5), range1.intersection(range2));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(3, 5);
+        assertEquals(Range.closed(3, 5), range1.intersection(range2));
+        assertEquals(Range.closed(3, 5), range2.intersection(range1));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(2, 4);
+        assertEquals(Range.closed(2, 4), range1.intersection(range2));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(1, 3);
+        assertEquals(Range.closed(1, 3), range1.intersection(range2));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(1, 5);
+        assertEquals(Range.closed(1, 5), range1.intersection(range2));
+
+        range1 = Range.closed(1, 5);
+        range2 = Range.closed(5, 5);
+        assertEquals(Range.closed(5, 5), range1.intersection(range2));
+    }
+
+    @Test
+    public void testIntersection_openBounds() {
+        Range<Integer> range1 = Range.openClosed(1, 5);
+        Range<Integer> range2 = Range.closed(3, 7);
+        assertEquals(Range.closed(3, 5), range1.intersection(range2));
+
+        range1 = Range.openClosed(1, 5);
+        range2 = Range.closed(6, 7);
+        assertNull(range1.intersection(range2));
+
+        range1 = Range.openClosed(1, 5);
+        range2 = Range.closed(5, 7);
+        assertEquals(Range.closed(5, 5), range1.intersection(range2));
+
+        range1 = Range.openClosed(4, 6);
+        range2 = Range.closed(1, 5);
+        assertEquals(Range.openClosed(4, 5), range1.intersection(range2));
+
+        range1 = Range.closedOpen(1, 5);
+        range2 = Range.closed(3, 5);
+        assertEquals(Range.closedOpen(3, 5), range1.intersection(range2));
+
+        range1 = Range.openClosed(1, 5);
+        range2 = Range.closed(2, 4);
+        assertEquals(Range.closed(2, 4), range1.intersection(range2));
+
+        range1 = Range.open(1, 5);
+        range2 = Range.closed(1, 3);
+        assertEquals(Range.openClosed(1, 3), range1.intersection(range2));
+
+        range1 = Range.open(1, 5);
+        range2 = Range.closed(1, 5);
+        assertEquals(Range.open(1, 5), range1.intersection(range2));
+
+        range1 = Range.closed(1, 10);
+        range2 = Range.open(2, 4);
+        assertEquals(Range.open(2, 4), range1.intersection(range2));
+
+        range1 = Range.open(1, 10);
+        range2 = Range.closed(2, 5);
+        assertEquals(Range.closed(2, 5), range1.intersection(range2));
+
+        range1 = Range.openClosed(1, 5);
+        range2 = Range.closed(1, 5);
+        assertEquals(Range.openClosed(1, 5), range1.intersection(range2));
+
+        range1 = Range.closedOpen(1, 5);
+        range2 = Range.closed(1, 5);
+        assertEquals(Range.closedOpen(1, 5), range1.intersection(range2));
+    }
+
+    @Test
+    public void testIntersection_atLeastAtMost(){
+        Range<Integer> range1 = Range.atLeast(1);
+        Range<Integer> range2 = Range.atLeast(5);
+        assertEquals(Range.atLeast(5), range1.intersection(range2));
+
+        range1 = Range.atMost(1);
+        range2 = Range.atMost(5);
+        assertEquals(Range.atMost(1), range1.intersection(range2));
+    }
+
+    @Test
+    public void testRangeLexComparator() {
+        List<Range<Integer>> ranges = Arrays.asList(
+                Range.closed(1, 3),
+                Range.closed(2, 4),
+                Range.closed(1, 4),
+                Range.closed(2, 3),
+                Range.closed(7, 10),
+                Range.closed(3, 4),
+                Range.closed(1, 2));
+        ranges.sort(Range.RANGE_LEX_COMPARATOR);
+        assertEquals(
+                Arrays.asList(
+                        Range.closed(1, 2),
+                        Range.closed(1, 3),
+                        Range.closed(1, 4),
+                        Range.closed(2, 3),
+                        Range.closed(2, 4),
+                        Range.closed(3, 4),
+                        Range.closed(7, 10)),
+                ranges);
+    }
+
+    @Test
+    public void testRangeLexComparator_openBounds() {
+        List<Range<Integer>> ranges = Arrays.asList(
+                Range.closed(2, 4),
+                Range.closed(1, 4),
+                Range.closed(2, 3),
+                Range.atLeast(7),
+                Range.atMost(3),
+                Range.closed(3, 4),
+                Range.closed(1, 2));
+        ranges.sort(Range.RANGE_LEX_COMPARATOR);
+        assertEquals(
+                Arrays.asList(
+                    Range.atMost(3),
+                    Range.closed(1, 2),
+                    Range.closed(1, 4),
+                    Range.closed(2, 3),
+                    Range.closed(2, 4),
+                    Range.closed(3, 4),
+                    Range.atLeast(7)),
+                ranges);
+    }
+}
diff --git a/dexlib2/src/test/java/com/android/tools/smali/dexlib2/util/UnmodifiableRangeMapTest.java b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/util/UnmodifiableRangeMapTest.java
new file mode 100644
index 0000000..dead33e
--- /dev/null
+++ b/dexlib2/src/test/java/com/android/tools/smali/dexlib2/util/UnmodifiableRangeMapTest.java
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2024, Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.tools.smali.util;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+
+import com.android.tools.smali.util.Range;
+import com.android.tools.smali.util.UnmodifiableRangeMap;
+
+import java.util.Map;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class UnmodifiableRangeMapTest {
+
+  @Test
+  public void testEmpty() {
+    UnmodifiableRangeMap<Integer, String> map = UnmodifiableRangeMap.of();
+    Assert.assertNull(map.get(0));
+    Assert.assertNull(map.getEntry(0));
+  }
+  
+  @Test
+  public void testBuilder() {
+    UnmodifiableRangeMap<Integer, String> rangeMap =
+    UnmodifiableRangeMap.<Integer, String>builder()
+    .put(Range.closed(1, 3), "a")
+    .put(Range.closed(4, 6), "b")
+    .build();
+    assertEquals("a", rangeMap.get(2));
+    assertEquals("b", rangeMap.get(5));
+    assertNull(rangeMap.get(0));
+    assertNull(rangeMap.get(7));
+    assertNull(rangeMap.get(null));
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testBuilderEmptyRange() {
+    UnmodifiableRangeMap.<Integer, String>builder().put(Range.open(1, 1), "a").build();
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testBuilderOverlappingRanges() {
+    UnmodifiableRangeMap.<Integer, String>builder()
+        .put(Range.closed(1, 3), "a")
+        .put(Range.closed(2, 4), "b")
+        .build();
+  }
+
+  @Test(expected = IllegalArgumentException.class)
+  public void testBuilderEdgeOverlappingRanges() {
+    UnmodifiableRangeMap.<Integer, String>builder()
+        .put(Range.closed(1, 3), "a")
+        .put(Range.closed(3, 7), "b")
+        .build();
+  }
+
+  @Test
+  public void testGet_oddSizeMap() {
+    UnmodifiableRangeMap<Integer, String> rangeMap =
+        UnmodifiableRangeMap.<Integer, String>builder()
+            .put(Range.closed(1, 3), "a")
+            .put(Range.closed(4, 6), "b")
+            .put(Range.closed(11, 20), "c")
+            .build();
+    assertEquals("a", rangeMap.get(2));
+    assertEquals("c", rangeMap.get(15));
+    assertNull(rangeMap.get(0));
+    assertNull(rangeMap.get(7));
+  }
+
+  @Test
+  public void testGet_evenSizeMap() {
+    UnmodifiableRangeMap<Integer, String> rangeMap =
+        UnmodifiableRangeMap.<Integer, String>builder()
+            .put(Range.closed(1, 3), "a")
+            .put(Range.closed(4, 6), "b")
+            .put(Range.closed(11, 20), "c")
+            .put(Range.closed(21, 30), "d")
+            .build();
+    assertEquals("a", rangeMap.get(2));
+    assertEquals("b", rangeMap.get(6));
+    assertEquals("c", rangeMap.get(15));
+    assertEquals("d", rangeMap.get(23));
+    assertNull(rangeMap.get(0));
+    assertNull(rangeMap.get(7));
+  }
+
+  @Test
+  public void testEntry() {
+    UnmodifiableRangeMap<Integer, String> rangeMap =
+        UnmodifiableRangeMap.<Integer, String>builder()
+            .put(Range.closed(1, 3), "a")
+            .put(Range.closed(4, 6), "b")
+            .put(Range.closed(10, 15), "c")
+            .build();
+    Map.Entry<Range<Integer>, String> entry = rangeMap.getEntry(2);
+    assertEquals(Range.closed(1, 3), entry.getKey());
+    assertEquals("a", entry.getValue());
+    assertNull(rangeMap.getEntry(null));
+  }
+
+  @Test
+  public void testRanges_AtMostAtLeast() {
+    UnmodifiableRangeMap<Integer, String> rangeMap =
+        UnmodifiableRangeMap.<Integer, String>builder()
+            .put(Range.atMost(3), "a")
+            .put(Range.closed(10, 15), "b")
+            .put(Range.atLeast(25), "c")
+            .build();
+    assertEquals("a", rangeMap.get(2));
+    assertNull(rangeMap.get(5));
+    assertEquals("b", rangeMap.get(12));
+    assertEquals("c", rangeMap.get(30));
+    assertNull(rangeMap.get(null));
+  }
+
+  @Test
+  public void testRanges_openBounds() {
+    UnmodifiableRangeMap<Integer, String> rangeMap =
+        UnmodifiableRangeMap.<Integer, String>builder()
+            .put(Range.openClosed(1, 3), "a")
+            .put(Range.open(10, 15), "b")
+            .put(Range.closedOpen(25, 30), "c")
+            .build();
+
+    assertNull(rangeMap.get(0));
+    assertNull(rangeMap.get(1));
+    assertEquals("a", rangeMap.get(2));
+    assertEquals("b", rangeMap.get(12));
+    assertNull(rangeMap.get(5));
+    assertNull(rangeMap.get(15));
+    assertEquals("c", rangeMap.get(25));
+    assertEquals("c", rangeMap.get(25));
+  }
+}
\ No newline at end of file
diff --git a/dexlib2/src/test/java/com/android/tools/smali/util/ArraySortedSetTest.java b/dexlib2/src/test/java/com/android/tools/smali/util/ArraySortedSetTest.java
new file mode 100644
index 0000000..658ad4d
--- /dev/null
+++ b/dexlib2/src/test/java/com/android/tools/smali/util/ArraySortedSetTest.java
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2024, Google LLC
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google LLC nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.tools.smali.util;
+
+import java.util.Arrays;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Iterator;
+
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@RunWith(JUnit4.class)
+public class ArraySortedSetTest {
+    @Test
+    public void testOf() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(), new Integer[] {
+                1, 2, 3
+        });
+        Assert.assertEquals(set.size(), 3);
+        Assert.assertTrue(set.contains(1));
+        Assert.assertTrue(set.contains(2));
+        Assert.assertTrue(set.contains(3));
+        Assert.assertFalse(set.contains(4));
+    }
+
+    @Test
+    public void testOfCollection() {
+        List<Integer> list = Arrays.asList(1, 2, 3);
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(), list);
+        Assert.assertEquals(set.size(), 3);
+        Assert.assertTrue(set.contains(1));
+        Assert.assertTrue(set.contains(2));
+        Assert.assertTrue(set.contains(3));
+        Assert.assertFalse(set.contains(4));
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testOfUnsorted() {
+        ArraySortedSet.of(Comparator.naturalOrder(), new Integer[] {
+                3, 1, 2
+        });
+    }
+
+    @Test(expected = AssertionError.class)
+    public void testOfCollectionUnsorted() {
+        ArraySortedSet.of(Comparator.naturalOrder(), Arrays.asList(3, 1, 2));
+    }
+
+    @Test
+    public void testIterator() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        Iterator<Integer> it = set.iterator();
+        Assert.assertEquals(it.next(), (Integer) 1);
+        Assert.assertEquals(it.next(), (Integer) 2);
+        Assert.assertEquals(it.next(), (Integer) 3);
+    }
+
+    @Test
+    public void testToArray() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        Assert.assertArrayEquals(set.toArray(), new Integer[] {
+                1, 2, 3
+        });
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testAdd() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        set.add(4);
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemove() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        set.remove(2);
+    }
+
+    @Test
+    public void testContainsAll() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        Assert.assertTrue(set.containsAll(Arrays.asList(1, 2)));
+        Assert.assertTrue(set.containsAll(Arrays.asList(1, 2, 3)));
+        Assert.assertFalse(set.containsAll(Arrays.asList(1, 2, 3, 4)));
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testAddAll() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        set.addAll(Arrays.asList(4));
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testRemoveAll() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        set.removeAll(Arrays.asList(2));
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testClear() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        set.clear();
+    }
+
+    @Test
+    public void testComparator() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        Assert.assertEquals(set.comparator(), Comparator.naturalOrder());
+    }
+
+    @Test
+    public void testFirst() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        Assert.assertEquals(set.first(), (Integer) 1);
+    }
+
+    @Test
+    public void testLast() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        Assert.assertEquals(set.last(), (Integer) 3);
+    }
+
+    @Test
+    public void testHashCode() {
+        ArraySortedSet<Integer> set = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        Assert.assertEquals(set.hashCode(), 6);
+    }
+
+    @Test
+    public void testEquals() {
+        ArraySortedSet<Integer> set1 = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        ArraySortedSet<Integer> set2 = ArraySortedSet.of(Comparator.naturalOrder(),
+                Arrays.asList(1, 2, 3));
+        Assert.assertTrue(set1.equals(set2));
+    }
+}
diff --git a/smali/Android.bp b/smali/Android.bp
index 73ec652..4184deb 100644
--- a/smali/Android.bp
+++ b/smali/Android.bp
@@ -34,6 +34,7 @@
     manifest: "manifest.txt",
 
     static_libs: [
+        "guava",
         "antlr-runtime",
         "jcommander",
         "smali-dexlib2",
@@ -43,4 +44,4 @@
     java_resources: [":android-smali_version"],
 
     wrapper: ":android-smali_script",
-}
\ No newline at end of file
+}