Merge commit '3e459092c91ca49ad0f61e8ba3bd72c20480aa0b' into dev-release
diff --git a/build.gradle b/build.gradle
index 49d3ecf..7123eb7 100644
--- a/build.gradle
+++ b/build.gradle
@@ -2315,7 +2315,7 @@
                 if (desc.parent == null) {
                     def sortedTimes = testTimes.sort({ e1, e2 -> e2.value <=> e1.value })
                     sortedTimes.eachWithIndex { key, value, i ->
-                        if (i < numberOfTestTimesToPrint) println "$key: $value"
+                        println "$key: $value"
                     }
                 }
             }
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json
index f47fe72..f3d0764 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -1,5 +1,5 @@
 {
-  "identifier": "com.tools.android:desugar_jdk_libs_configuration:2.0.2",
+  "identifier": "com.tools.android:desugar_jdk_libs_configuration:2.0.1",
   "configuration_format_version": 100,
   "required_compilation_api_level": 30,
   "synthesized_library_classes_package_prefix": "j$.",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json b/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
index 46a6562..7a72f81 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
@@ -2,7 +2,7 @@
   "configuration_format_version": 5,
   "group_id": "com.tools.android",
   "artifact_id": "desugar_jdk_libs",
-  "version": "1.2.5",
+  "version": "1.2.3",
   "required_compilation_api_level": 33,
   "synthesized_library_classes_package_prefix": "j$.",
   "support_all_callbacks_from_library": true,
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_minimal.json b/src/library_desugar/jdk11/desugar_jdk_libs_minimal.json
index 15939bc..119b674 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_minimal.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_minimal.json
@@ -1,5 +1,5 @@
 {
-  "identifier": "com.tools.android:desugar_jdk_libs_configuration_minimal:2.0.2",
+  "identifier": "com.tools.android:desugar_jdk_libs_configuration_minimal:2.0.1",
   "configuration_format_version": 100,
   "required_compilation_api_level": 24,
   "synthesized_library_classes_package_prefix": "j$.",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
index e963121..5269d86 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_nio.json
@@ -1,5 +1,5 @@
 {
-  "identifier": "com.tools.android:desugar_jdk_libs_configuration_nio:2.0.2",
+  "identifier": "com.tools.android:desugar_jdk_libs_configuration_nio:2.0.1",
   "configuration_format_version": 100,
   "required_compilation_api_level": 30,
   "synthesized_library_classes_package_prefix": "j$.",
diff --git a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
index 5a0bd81..60f5fe4 100644
--- a/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
+++ b/src/main/java/com/android/tools/r8/androidapi/AndroidApiLevelCompute.java
@@ -74,6 +74,9 @@
     return new KnownApiLevel(options.getMinApiLevel());
   }
 
+  // TODO(b/213552119): This should not be necessary if we have an api computation that returns min
+  //  api if we have platform.
+  @Deprecated
   public ComputedApiLevel getPlatformApiLevelOrUnknown(AppView<?> appView) {
     if (appView.options().getMinApiLevel() == AndroidApiLevel.ANDROID_PLATFORM) {
       return ComputedApiLevel.platform();
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index 23b16cc..894227d 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -302,7 +302,10 @@
     private final Queue<DexClasspathClass> classpathClasses = new ConcurrentLinkedQueue<>();
     private final Queue<DexLibraryClass> libraryClasses = new ConcurrentLinkedQueue<>();
     // Jar application reader to share across all class readers.
-    private final JarApplicationReader application = new JarApplicationReader(options);
+    private final DexApplicationReadFlags.Builder readFlagsBuilder =
+        DexApplicationReadFlags.builder();
+    private final JarApplicationReader application =
+        new JarApplicationReader(options, readFlagsBuilder);
 
     // Flag of which input resource types have flown into the program classes.
     // Note that this is just at the level of the resources having been given.
@@ -317,12 +320,10 @@
     }
 
     public DexApplicationReadFlags getDexApplicationReadFlags() {
-      return new DexApplicationReadFlags(
-          hasReadProgramResourceFromDex,
-          hasReadProgramResourceFromCf,
-          application.getRecordWitnesses(),
-          application.getVarHandleWitnesses(),
-          application.getMethodHandlesLookupWitnesses());
+      return readFlagsBuilder
+          .setHasReadProgramClassFromDex(hasReadProgramResourceFromDex)
+          .setHasReadProgramClassFromCf(hasReadProgramResourceFromCf)
+          .build();
     }
 
     private void readDexSources(List<ProgramResource> dexSources, Queue<DexProgramClass> classes)
diff --git a/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java b/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
index 34898725..8e51a2e 100644
--- a/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
+++ b/src/main/java/com/android/tools/r8/graph/ApplicationReaderMap.java
@@ -8,8 +8,6 @@
 
 public abstract class ApplicationReaderMap {
 
-  public static ApplicationReaderMap INSTANCE;
-
   public abstract String getDescriptor(String descriptor);
 
   public abstract DexType getType(DexType type);
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplicationReadFlags.java b/src/main/java/com/android/tools/r8/graph/DexApplicationReadFlags.java
index f949455..2032e29 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplicationReadFlags.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplicationReadFlags.java
@@ -3,19 +3,76 @@
 // BSD-style license that can be found in the LICENSE file.
 package com.android.tools.r8.graph;
 
+import com.google.common.collect.ImmutableSet;
 import java.util.Set;
 
 // Flags set based on the application when it was read.
 // Note that in r8, once classes are pruned, the flags may not reflect the application anymore.
 public class DexApplicationReadFlags {
 
+  public static class Builder {
+
+    private boolean hasReadProgramClassFromDex;
+    private boolean hasReadProgramClassFromCf;
+    private final ImmutableSet.Builder<DexType> recordWitnessesBuilder = ImmutableSet.builder();
+    private final ImmutableSet.Builder<DexType> varHandleWitnessesBuilder = ImmutableSet.builder();
+    private final ImmutableSet.Builder<DexType> methodHandlesLookupWitnessesBuilder =
+        ImmutableSet.builder();
+
+    private Builder() {}
+
+    public Builder setHasReadProgramClassFromDex(boolean value) {
+      hasReadProgramClassFromDex = value;
+      return this;
+    }
+
+    public Builder setHasReadProgramClassFromCf(boolean value) {
+      hasReadProgramClassFromCf = value;
+      return this;
+    }
+
+    public Builder addRecordWitness(DexType witness) {
+      synchronized (recordWitnessesBuilder) {
+        recordWitnessesBuilder.add(witness);
+      }
+      return this;
+    }
+
+    public Builder addVarHandleWitness(DexType witness) {
+      synchronized (varHandleWitnessesBuilder) {
+        varHandleWitnessesBuilder.add(witness);
+      }
+      return this;
+    }
+
+    public Builder addMethodHandlesLookupWitness(DexType witness) {
+      synchronized (methodHandlesLookupWitnessesBuilder) {
+        methodHandlesLookupWitnessesBuilder.add(witness);
+      }
+      return this;
+    }
+
+    public DexApplicationReadFlags build() {
+      return new DexApplicationReadFlags(
+          hasReadProgramClassFromDex,
+          hasReadProgramClassFromCf,
+          recordWitnessesBuilder.build(),
+          varHandleWitnessesBuilder.build(),
+          methodHandlesLookupWitnessesBuilder.build());
+    }
+  }
+
   private final boolean hasReadProgramClassFromDex;
   private final boolean hasReadProgramClassFromCf;
   private final Set<DexType> recordWitnesses;
   private final Set<DexType> varHandleWitnesses;
   private final Set<DexType> methodHandlesLookupWitnesses;
 
-  public DexApplicationReadFlags(
+  public static Builder builder() {
+    return new Builder();
+  }
+
+  private DexApplicationReadFlags(
       boolean hasReadProgramClassFromDex,
       boolean hasReadProgramClassFromCf,
       Set<DexType> recordWitnesses,
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 57d6d34..4df3ab0 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -362,6 +362,14 @@
   public final DexString getString = createString("get");
   public final DexString setString = createString("set");
   public final DexString compareAndSetString = createString("compareAndSet");
+  public final DexString weakCompareAndSetString = createString("weakCompareAndSet");
+  public final DexString getVolatileString = createString("getVolatile");
+  public final DexString setVolatileString = createString("setVolatile");
+  public final DexString setReleaseString = createString("setRelease");
+
+  // Method names used on MethodHandles.
+  public final DexString lookupString = createString("lookup");
+  public final DexString privateLookupInString = createString("privateLookupIn");
 
   public final DexType booleanType = createStaticallyKnownType(booleanDescriptor);
   public final DexType byteType = createStaticallyKnownType(byteDescriptor);
@@ -2259,7 +2267,7 @@
     private final DexProto setSignature = createProto(voidType, objectArrayType);
     private final DexProto compareAndSetSignature = createProto(booleanType, objectArrayType);
 
-    private final Set<DexString> varHandleMethods =
+    public final Set<DexString> varHandleMethodsWithPolymorphicReturnType =
         createStrings(
             "compareAndExchange",
             "compareAndExchangeAcquire",
@@ -2285,12 +2293,12 @@
             "getVolatile");
 
     private final Set<DexString> varHandleSetMethods =
-        createStrings(setString, "setOpaque", "setRelease", "setVolatile");
+        createStrings(setString, "setOpaque", setReleaseString, setVolatileString);
 
     public final Set<DexString> varHandleCompareAndSetMethodNames =
         createStrings(
             compareAndSetString,
-            "weakCompareAndSet",
+            weakCompareAndSetString,
             "weakCompareAndSetAcquire",
             "weakCompareAndSetPlain",
             "weakCompareAndSetRelease");
@@ -2302,7 +2310,7 @@
           result = createMethod(methodHandleType, signature, invokeProto.name);
         }
       } else if (invokeProto.holder == varHandleType) {
-        if (varHandleMethods.contains(invokeProto.name)) {
+        if (varHandleMethodsWithPolymorphicReturnType.contains(invokeProto.name)) {
           result = createMethod(varHandleType, signature, invokeProto.name);
         } else if (varHandleSetMethods.contains(invokeProto.name)) {
           result = createMethod(varHandleType, setSignature, invokeProto.name);
@@ -2329,7 +2337,7 @@
         return invokeProto.name == invokeMethodName || invokeProto.name == invokeExactMethodName;
       }
       if (invokeProto.holder == varHandleType) {
-        return varHandleMethods.contains(invokeProto.name)
+        return varHandleMethodsWithPolymorphicReturnType.contains(invokeProto.name)
             || varHandleSetMethods.contains(invokeProto.name)
             || varHandleCompareAndSetMethodNames.contains(invokeProto.name);
       }
diff --git a/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java b/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
index 93e56a7..2f957dd 100644
--- a/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarApplicationReader.java
@@ -8,9 +8,7 @@
 import com.android.tools.r8.ir.desugar.varhandle.VarHandleDesugaring;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.InternalOptions;
-import com.google.common.collect.Sets;
 import java.util.List;
-import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 import org.objectweb.asm.Type;
 
@@ -28,15 +26,17 @@
   private final ConcurrentHashMap<String, Type> asmTypeCache = new ConcurrentHashMap<>();
   private final ConcurrentHashMap<String, DexString> stringCache = new ConcurrentHashMap<>();
   private final ApplicationReaderMap applicationReaderMap;
-  private final Set<DexType> recordWitnesses = Sets.newConcurrentHashSet();
-  private final Set<DexType> varHandleWitnesses = Sets.newConcurrentHashSet();
-  private final Set<DexType> methodHandlesLookupWitnesses = Sets.newConcurrentHashSet();
+  private final DexApplicationReadFlags.Builder readFlagsBuilder;
 
-  private boolean hasReadRecordReferenceFromProgramClass = false;
+  public JarApplicationReader(
+      InternalOptions options, DexApplicationReadFlags.Builder readFlagsBuilder) {
+    this.options = options;
+    this.readFlagsBuilder = readFlagsBuilder;
+    applicationReaderMap = ApplicationReaderMap.getInstance(options);
+  }
 
   public JarApplicationReader(InternalOptions options) {
-    this.options = options;
-    applicationReaderMap = ApplicationReaderMap.getInstance(options);
+    this(options, DexApplicationReadFlags.builder());
   }
 
   public Type getAsmObjectType(String name) {
@@ -160,14 +160,10 @@
 
   public void addRecordWitness(DexType witness, ClassKind<?> classKind) {
     if (classKind == ClassKind.PROGRAM) {
-      recordWitnesses.add(witness);
+      readFlagsBuilder.addRecordWitness(witness);
     }
   }
 
-  public Set<DexType> getRecordWitnesses() {
-    return recordWitnesses;
-  }
-
   public void checkFieldForRecord(DexField dexField, ClassKind<?> classKind) {
     if (options.shouldDesugarRecords() && RecordDesugaring.refersToRecord(dexField, getFactory())) {
       addRecordWitness(dexField.getHolderType(), classKind);
@@ -183,14 +179,10 @@
 
   public void addVarHandleWitness(DexType witness, ClassKind<?> classKind) {
     if (classKind == ClassKind.PROGRAM) {
-      varHandleWitnesses.add(witness);
+      readFlagsBuilder.addVarHandleWitness(witness);
     }
   }
 
-  public Set<DexType> getVarHandleWitnesses() {
-    return varHandleWitnesses;
-  }
-
   public void checkFieldForVarHandle(DexField dexField, ClassKind<?> classKind) {
     if (options.shouldDesugarVarHandle()
         && VarHandleDesugaring.refersToVarHandle(dexField, getFactory())) {
@@ -207,12 +199,33 @@
 
   public void addMethodHandlesLookupWitness(DexType witness, ClassKind<?> classKind) {
     if (classKind == ClassKind.PROGRAM) {
-      methodHandlesLookupWitnesses.add(witness);
+      readFlagsBuilder.addMethodHandlesLookupWitness(witness);
     }
   }
 
-  public Set<DexType> getMethodHandlesLookupWitnesses() {
-    return methodHandlesLookupWitnesses;
+  public void checkClassForMethodHandlesLookup(DexClass dexClass, ClassKind<?> classKind) {
+    if (options.shouldDesugarVarHandle()) {
+      if (VarHandleDesugaring.refersToMethodHandlesLookup(dexClass.getType(), getFactory())) {
+        addVarHandleWitness(dexClass.getType(), classKind);
+      }
+      dexClass
+          .getInnerClasses()
+          .forEach(
+              attribute -> {
+                // MethodHandles$Lookup has no inner classes.
+                assert !VarHandleDesugaring.refersToMethodHandlesLookup(
+                    attribute.getOuter(), getFactory());
+                if (VarHandleDesugaring.refersToMethodHandlesLookup(
+                    attribute.getInner(), getFactory())) {
+                  addMethodHandlesLookupWitness(dexClass.getType(), classKind);
+                  // When the inner MethodHandles$Lookup is present the outer is MethodHandles, and
+                  // in that case the enqueuer will process all methods in the library class
+                  // MethodHandles which have references to VarHandle.
+                  assert attribute.getOuter() == getFactory().methodHandlesType;
+                  addVarHandleWitness(dexClass.getType(), classKind);
+                }
+              });
+    }
   }
 
   public void checkFieldForMethodHandlesLookup(DexField dexField, ClassKind<?> classKind) {
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index fe8d9e4..76ca9ac 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -487,6 +487,7 @@
               application.getFactory().getSkipNameValidationForTesting(),
               getChecksumSupplier(classKind),
               syntheticMarker);
+      application.checkClassForMethodHandlesLookup(clazz, classKind);
       InnerClassAttribute innerClassAttribute = clazz.getInnerClassAttributeForThisClass();
       // A member class should not be a local or anonymous class.
       if (innerClassAttribute != null && innerClassAttribute.getOuter() != null) {
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
index 80bb4cf..ee98d51 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -22,6 +22,7 @@
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.function.Function;
+import java.util.function.Predicate;
 import java.util.stream.Collectors;
 
 public class LazyLoadedDexApplication extends DexApplication {
@@ -140,10 +141,18 @@
         ProgramClassCollection programClassesLoader,
         InternalOptions options) {
 
+      // When desugaring VarHandle do not read the VarHandle and MethodHandles$Lookup classes
+      // from the library as they will be synthesized during desugaring.
+      Predicate<DexType> forceLoadPredicate =
+          type ->
+              !(options.shouldDesugarVarHandle()
+                  && (type == options.dexItemFactory().varHandleType
+                      || type == options.dexItemFactory().lookupType));
+
       // Force-load library classes.
       ImmutableMap<DexType, DexLibraryClass> allLibraryClasses;
       if (libraryClassesLoader != null) {
-        libraryClassesLoader.forceLoad(type -> true);
+        libraryClassesLoader.forceLoad(forceLoadPredicate);
         allLibraryClasses = libraryClassesLoader.getAllClassesInMap();
       } else {
         allLibraryClasses = ImmutableMap.of();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
index bc61d60..8b46407 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecificationParser.java
@@ -10,7 +10,6 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineDesugaredLibrarySpecificationParser;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.synthesis.SyntheticNaming;
 import com.android.tools.r8.utils.ExceptionDiagnostic;
 import com.android.tools.r8.utils.Reporter;
 import com.android.tools.r8.utils.StringDiagnostic;
@@ -58,7 +57,7 @@
     // It can hardly be written by hand and is always generated.
     if (isMachineSpecification(jsonConfig, reporter, origin)) {
       return new MachineDesugaredLibrarySpecificationParser(
-              dexItemFactory, reporter, libraryCompilation, minAPILevel, new SyntheticNaming())
+              dexItemFactory, reporter, libraryCompilation, minAPILevel)
           .parse(origin, jsonConfigString, jsonConfig);
     }
     // Human Specification is the easy to write format for developers and allows one to widely use
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/DerivedMethod.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/DerivedMethod.java
index dde1f48..714cef4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/DerivedMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/DerivedMethod.java
@@ -4,10 +4,12 @@
 
 package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
 
+import com.android.tools.r8.graph.AppView;
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexString;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.synthesis.SyntheticNaming;
 import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import java.util.Objects;
 
@@ -20,21 +22,29 @@
 public class DerivedMethod implements SpecificationDescriptor {
 
   private final DexMethod method;
-  private final SyntheticKind holderKind;
+  private final MachineSyntheticKind.Kind holderKind;
 
   public DerivedMethod(DexMethod method) {
     this(method, null);
   }
 
-  public DerivedMethod(DexMethod method, SyntheticKind holderKind) {
+  public DerivedMethod(DexMethod method, MachineSyntheticKind.Kind holderKind) {
     this.holderKind = holderKind;
     this.method = method;
   }
 
-  public SyntheticKind getHolderKind() {
+  public MachineSyntheticKind.Kind getMachineHolderKind() {
     return holderKind;
   }
 
+  public SyntheticKind getHolderKind(AppView<?> appView) {
+    return getHolderKind(appView.getSyntheticItems().getNaming());
+  }
+
+  public SyntheticKind getHolderKind(SyntheticNaming naming) {
+    return holderKind == null ? null : holderKind.asSyntheticKind(naming);
+  }
+
   public DexType getHolderContext() {
     return method.getHolderType();
   }
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecificationParser.java
index 031ca29..0d03018 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecificationParser.java
@@ -42,8 +42,6 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.memberparser.MachineFieldParser;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.memberparser.MachineMethodParser;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.synthesis.SyntheticNaming;
-import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.ExceptionDiagnostic;
@@ -74,7 +72,6 @@
   private final Reporter reporter;
   private final boolean libraryCompilation;
   private final int minAPILevel;
-  private final SyntheticNaming syntheticNaming;
 
   private Origin origin;
   private JsonObject jsonConfig;
@@ -84,14 +81,12 @@
       DexItemFactory dexItemFactory,
       Reporter reporter,
       boolean libraryCompilation,
-      int minAPILevel,
-      SyntheticNaming syntheticNaming) {
+      int minAPILevel) {
     this.dexItemFactory = dexItemFactory;
     this.methodParser = new MachineMethodParser(dexItemFactory, this::stringDescriptorToDexType);
     this.fieldParser = new MachineFieldParser(dexItemFactory, this::stringDescriptorToDexType);
     this.reporter = reporter;
     this.minAPILevel = minAPILevel;
-    this.syntheticNaming = syntheticNaming;
     this.libraryCompilation = libraryCompilation;
   }
 
@@ -425,8 +420,7 @@
     if (kind == -1) {
       return new DerivedMethod(dexMethod);
     }
-    SyntheticKind syntheticKind = syntheticNaming.fromId(kind);
-    return new DerivedMethod(dexMethod, syntheticKind);
+    return new DerivedMethod(dexMethod, MachineSyntheticKind.fromId(kind));
   }
 
   private List<DexMethod> parseMethodList(JsonArray array) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineSyntheticKind.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineSyntheticKind.java
new file mode 100644
index 0000000..30ae324
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineSyntheticKind.java
@@ -0,0 +1,63 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
+
+import com.android.tools.r8.synthesis.SyntheticNaming;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
+
+/**
+ * The synthetic kind ids are not stable across compiler version. We need here to have stable ids so
+ * that we can write the machine specification using the id.
+ */
+public class MachineSyntheticKind {
+
+  // These ids should remain stable across compiler versions or it will break machine specification
+  // parsing. The ids chosen were the ids used when generating the 2.0.0 specification (before that
+  // issue was reported in b/262692506).
+  private static final int RETARGET_INTERFACE_ID = 11;
+  private static final int RETARGET_CLASS_ID = 10;
+  private static final int COMPANION_CLASS_ID = 8;
+  private static final int EMULATED_INTERFACE_CLASS_ID = 9;
+
+  public static Kind fromId(int id) {
+    for (Kind kind : Kind.values()) {
+      if (kind.getId() == id) {
+        return kind;
+      }
+    }
+    return null;
+  }
+
+  public enum Kind {
+    RETARGET_INTERFACE(RETARGET_INTERFACE_ID),
+    RETARGET_CLASS(RETARGET_CLASS_ID),
+    COMPANION_CLASS(COMPANION_CLASS_ID),
+    EMULATED_INTERFACE_CLASS(EMULATED_INTERFACE_CLASS_ID);
+
+    private final int id;
+
+    Kind(int id) {
+      this.id = id;
+    }
+
+    public int getId() {
+      return id;
+    }
+
+    public SyntheticKind asSyntheticKind(SyntheticNaming naming) {
+      switch (this) {
+        case RETARGET_INTERFACE:
+          return naming.RETARGET_INTERFACE;
+        case RETARGET_CLASS:
+          return naming.RETARGET_CLASS;
+        case COMPANION_CLASS:
+          return naming.COMPANION_CLASS;
+        case EMULATED_INTERFACE_CLASS:
+          return naming.EMULATED_INTERFACE_CLASS;
+      }
+      return null;
+    }
+  }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.java
index f5d81fa..c232dff 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MultiAPILevelMachineDesugaredLibrarySpecificationJsonExporter.java
@@ -315,7 +315,9 @@
     String methodString = toString(derivedMethod.getMethod());
     String holderKindString =
         Integer.toString(
-            derivedMethod.getHolderKind() == null ? -1 : derivedMethod.getHolderKind().getId());
+            derivedMethod.getMachineHolderKind() == null
+                ? -1
+                : derivedMethod.getMachineHolderKind().getId());
     return new Object[] {methodString, holderKindString};
   }
 
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
index 8e6aca3..ae5814a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeterSyntheticHelper.java
@@ -91,7 +91,7 @@
   }
 
   DexMethod forwardingMethod(EmulatedDispatchMethodDescriptor descriptor) {
-    assert descriptor.getForwardingMethod().getHolderKind() == null;
+    assert descriptor.getForwardingMethod().getHolderKind(appView) == null;
     return descriptor.getForwardingMethod().getMethod();
   }
 
@@ -103,7 +103,7 @@
 
   private boolean verifyKind(DerivedMethod method, SyntheticKindSelector kindSelector) {
     SyntheticKind kind = kindSelector.select(appView.getSyntheticItems().getNaming());
-    assert method.getHolderKind().equals(kind);
+    assert method.getHolderKind(appView).equals(kind);
     return true;
   }
 
@@ -139,7 +139,7 @@
           appView
               .getSyntheticItems()
               .getExistingFixedClass(
-                  ignored -> emulatedDispatchMethod.getHolderKind(), holderContext, appView);
+                  ignored -> emulatedDispatchMethod.getHolderKind(appView), holderContext, appView);
       DexMethod dispatchMethod =
           emulatedHolderDispatchMethod(syntheticClass.type, emulatedDispatchMethod);
       assert syntheticClass.lookupMethod(dispatchMethod) != null;
@@ -177,7 +177,7 @@
     appView
         .getSyntheticItems()
         .ensureFixedClass(
-            ignored -> emulatedDispatchMethod.getHolderKind(),
+            ignored -> emulatedDispatchMethod.getHolderKind(appView),
             holderContext,
             appView,
             classBuilder -> buildHolderDispatchMethod(classBuilder, itfClass, descriptor, null),
@@ -193,7 +193,7 @@
     if (appView.options().isDesugaredLibraryCompilation()) {
       return appView
           .getSyntheticItems()
-          .getExistingFixedClass(ignored -> itfMethod.getHolderKind(), itfContext, appView);
+          .getExistingFixedClass(ignored -> itfMethod.getHolderKind(appView), itfContext, appView);
     }
     ClasspathOrLibraryClass context = itfContext.asClasspathOrLibraryClass();
     assert context != null;
@@ -217,7 +217,7 @@
     return appView
         .getSyntheticItems()
         .ensureFixedClass(
-            ignore -> itfMethod.getHolderKind(),
+            ignore -> itfMethod.getHolderKind(appView),
             itfContext,
             appView,
             classBuilder -> buildInterfaceDispatchMethod(classBuilder, descriptor),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
index 00c7da1..15c644b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineEmulatedInterfaceConverter.java
@@ -16,7 +16,7 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedInterfaceDescriptor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
-import com.android.tools.r8.synthesis.SyntheticNaming;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSyntheticKind;
 import com.android.tools.r8.utils.WorkList;
 import com.google.common.collect.Sets;
 import java.util.ArrayList;
@@ -68,8 +68,8 @@
 
   private EmulatedDispatchMethodDescriptor computeEmulatedDispatchDescriptor(
       DexMethod method, HumanRewritingFlags rewritingFlags, AppInfoWithClassHierarchy appInfo) {
-    SyntheticNaming syntheticNaming = appInfo.getSyntheticItems().getNaming();
-    DerivedMethod forwardingMethod = new DerivedMethod(method, syntheticNaming.COMPANION_CLASS);
+    DerivedMethod forwardingMethod =
+        new DerivedMethod(method, MachineSyntheticKind.Kind.COMPANION_CLASS);
     DexMethod itfDexMethod =
         appInfo
             .dexItemFactory()
@@ -79,7 +79,7 @@
                 method.getName());
     DerivedMethod interfaceMethod = new DerivedMethod(itfDexMethod);
     DerivedMethod dispatchMethod =
-        new DerivedMethod(method, syntheticNaming.EMULATED_INTERFACE_CLASS);
+        new DerivedMethod(method, MachineSyntheticKind.Kind.EMULATED_INTERFACE_CLASS);
     LinkedHashMap<DexType, DerivedMethod> dispatchCases = getDispatchCases(rewritingFlags, method);
     return new EmulatedDispatchMethodDescriptor(
         interfaceMethod, dispatchMethod, forwardingMethod, dispatchCases);
@@ -110,7 +110,6 @@
       }
     }
     if (subInterfaces != null) {
-      SyntheticNaming syntheticNaming = appInfo.getSyntheticItems().getNaming();
       for (int i = subInterfaces.size() - 1; i >= 0; i--) {
         DexClass subInterfaceClass = appInfo.definitionFor(subInterfaces.get(i));
         assert subInterfaceClass != null;
@@ -122,7 +121,7 @@
           DexMethod reference = result.getReference();
           extraDispatchCases.put(
               subInterfaceClass.type,
-              new DerivedMethod(reference, syntheticNaming.COMPANION_CLASS));
+              new DerivedMethod(reference, MachineSyntheticKind.Kind.COMPANION_CLASS));
         }
       }
     } else {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
index 004c35f..1197688 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
@@ -17,7 +17,7 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.DerivedMethod;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.EmulatedDispatchMethodDescriptor;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
-import com.android.tools.r8.synthesis.SyntheticNaming;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineSyntheticKind;
 import com.android.tools.r8.utils.TraversalContinuation;
 import com.google.common.collect.Sets;
 import java.util.LinkedHashMap;
@@ -220,12 +220,11 @@
       return;
     }
     // TODO(b/184026720): Implement library boundaries.
-    SyntheticNaming syntheticNaming = appInfo.getSyntheticItems().getNaming();
     DerivedMethod forwardingMethod = new DerivedMethod(forwardingDexMethod);
     DerivedMethod interfaceMethod =
-        new DerivedMethod(src.getReference(), syntheticNaming.RETARGET_INTERFACE);
+        new DerivedMethod(src.getReference(), MachineSyntheticKind.Kind.RETARGET_INTERFACE);
     DerivedMethod dispatchMethod =
-        new DerivedMethod(src.getReference(), syntheticNaming.RETARGET_CLASS);
+        new DerivedMethod(src.getReference(), MachineSyntheticKind.Kind.RETARGET_CLASS);
     LinkedHashMap<DexType, DerivedMethod> dispatchCases = new LinkedHashMap<>();
     builder.putEmulatedVirtualRetarget(
         src.getReference(),
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
index 4ac2b73..0fa2592 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
@@ -147,7 +147,7 @@
 
   public boolean verifyKind(DerivedMethod method, SyntheticKindSelector kindSelector) {
     SyntheticKind kind = kindSelector.select(appView.getSyntheticItems().getNaming());
-    assert method.getHolderKind().equals(kind);
+    assert method.getHolderKind(appView).equals(kind);
     return true;
   }
 
@@ -158,7 +158,7 @@
   }
 
   DexMethod emulatedInterfaceInterfaceMethod(DerivedMethod method) {
-    assert method.getHolderKind() == null;
+    assert method.getHolderKind(appView) == null;
     return method.getMethod();
   }
 
@@ -275,7 +275,7 @@
   }
 
   DexMethod ensureEmulatedInterfaceForwardingMethod(DerivedMethod method) {
-    if (method.getHolderKind() == null) {
+    if (method.getHolderKind(appView) == null) {
       return method.getMethod();
     }
     assert verifyKind(method, kinds -> kinds.COMPANION_CLASS);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java
index 6aaf59d..d8382b7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaring.java
@@ -133,7 +133,7 @@
     return refersToVarHandle(field.type, factory);
   }
 
-  private static boolean refersToMethodHandlesLookup(DexType type, DexItemFactory factory) {
+  public static boolean refersToMethodHandlesLookup(DexType type, DexItemFactory factory) {
     if (type == factory.desugarMethodHandlesLookupType) {
       // All references to java.lang.invoke.MethodHandles$Lookup is rewritten during application
       // writing.
@@ -251,13 +251,21 @@
         && holder != factory.varHandleType) {
       return DesugarDescription.nothing();
     }
+
     DexMethod method = invoke.getMethod();
     if (method.getHolderType() == factory.methodHandlesType) {
-      if (method.getName().equals(factory.createString("lookup"))
+      if (method.getName().equals(factory.lookupString)
           && method.getReturnType() == factory.lookupType
           && method.getArity() == 0
           && invoke.isInvokeStatic()) {
         return computeMethodHandlesLookup(factory);
+      } else if (method.getName().equals(factory.privateLookupInString)
+          && method.getReturnType() == factory.lookupType
+          && method.getArity() == 2
+          && method.getParameter(0) == factory.classType
+          && method.getParameter(1) == factory.lookupType
+          && invoke.isInvokeStatic()) {
+        return computeMethodHandlesPrivateLookupIn(factory);
       } else if (method.getName().equals(factory.createString("arrayElementVarHandle"))
           && method.getReturnType() == factory.varHandleType
           && method.getArity() == 1
@@ -279,14 +287,16 @@
       assert invoke.isInvokeVirtual();
       DexString name = method.getName();
       int arity = method.getProto().getArity();
-      // TODO(b/247076137): Support two coordinates (array element VarHandle).
-      if (name.equals(factory.compareAndSetString)) {
+      if (name.equals(factory.compareAndSetString)
+          || name.equals(factory.weakCompareAndSetString)) {
         assert arity == 3 || arity == 4;
         return computeDesugarSignaturePolymorphicMethod(invoke, arity - 2);
-      } else if (name.equals(factory.getString)) {
+      } else if (name.equals(factory.getString) || name.equals(factory.getVolatileString)) {
         assert arity == 1 || arity == 2;
         return computeDesugarSignaturePolymorphicMethod(invoke, arity);
-      } else if (name.equals(factory.setString)) {
+      } else if (name.equals(factory.setString)
+          || name.equals(factory.setVolatileString)
+          || name.equals(factory.setReleaseString)) {
         assert arity == 2 || arity == 3;
         return computeDesugarSignaturePolymorphicMethod(invoke, arity - 1);
       } else {
@@ -306,17 +316,45 @@
                 eventConsumer,
                 context,
                 methodProcessingContext,
-                dexItemFactory) ->
-                ImmutableList.of(
-                    new CfNew(factory.lookupType),
-                    new CfStackInstruction(Opcode.Dup),
-                    new CfInvoke(
-                        Opcodes.INVOKESPECIAL,
-                        factory.createMethod(
-                            factory.lookupType,
-                            factory.createProto(factory.voidType),
-                            factory.constructorMethodName),
-                        false)))
+                dexItemFactory) -> {
+              ensureMethodHandlesLookupClass(eventConsumer, context);
+              localStackAllocator.allocateLocalStack(2);
+              return ImmutableList.of(
+                  new CfNew(factory.lookupType),
+                  new CfStackInstruction(Opcode.Dup),
+                  new CfInvoke(
+                      Opcodes.INVOKESPECIAL,
+                      factory.createMethod(
+                          factory.lookupType,
+                          factory.createProto(factory.voidType),
+                          factory.constructorMethodName),
+                      false));
+            })
+        .build();
+  }
+
+  public DesugarDescription computeMethodHandlesPrivateLookupIn(DexItemFactory factory) {
+    return DesugarDescription.builder()
+        .setDesugarRewrite(
+            (freshLocalProvider,
+                localStackAllocator,
+                eventConsumer,
+                context,
+                methodProcessingContext,
+                dexItemFactory) -> {
+              ensureMethodHandlesLookupClass(eventConsumer, context);
+              // Rewrite MethodHandles.privateLookupIn(class, lookup) to
+              // lookup.toPrivateLookupIn(class).
+              return ImmutableList.of(
+                  new CfStackInstruction(Opcode.Swap),
+                  new CfInvoke(
+                      Opcodes.INVOKEVIRTUAL,
+                      factory.createMethod(
+                          factory.lookupType,
+                          factory.createProto(factory.lookupType, factory.classType),
+                          factory.createString("toPrivateLookupIn")),
+                      false));
+            })
         .build();
   }
 
@@ -328,18 +366,20 @@
                 eventConsumer,
                 context,
                 methodProcessingContext,
-                dexItemFactory) ->
-                ImmutableList.of(
-                    new CfNew(factory.varHandleType),
-                    new CfStackInstruction(Opcode.DupX1),
-                    new CfStackInstruction(Opcode.Swap),
-                    new CfInvoke(
-                        Opcodes.INVOKESPECIAL,
-                        factory.createMethod(
-                            factory.varHandleType,
-                            factory.createProto(factory.voidType, factory.classType),
-                            factory.constructorMethodName),
-                        false)))
+                dexItemFactory) -> {
+              localStackAllocator.allocateLocalStack(2);
+              return ImmutableList.of(
+                  new CfNew(factory.varHandleType),
+                  new CfStackInstruction(Opcode.DupX1),
+                  new CfStackInstruction(Opcode.Swap),
+                  new CfInvoke(
+                      Opcodes.INVOKESPECIAL,
+                      factory.createMethod(
+                          factory.varHandleType,
+                          factory.createProto(factory.voidType, factory.classType),
+                          factory.constructorMethodName),
+                      false));
+            })
         .build();
   }
 
@@ -352,8 +392,11 @@
                 eventConsumer,
                 context,
                 methodProcessingContext,
-                dexItemFactory) ->
-                desugarSignaturePolymorphicMethod(invoke, coordinates, freshLocalProvider))
+                dexItemFactory) -> {
+              ensureVarHandleClass(eventConsumer, context);
+              return desugarSignaturePolymorphicMethod(
+                  invoke, coordinates, freshLocalProvider, localStackAllocator);
+            })
         .build();
   }
 
@@ -370,7 +413,10 @@
   }
 
   private Collection<CfInstruction> desugarSignaturePolymorphicMethod(
-      CfInvoke invoke, int coordinates, FreshLocalProvider freshLocalProvider) {
+      CfInvoke invoke,
+      int coordinates,
+      FreshLocalProvider freshLocalProvider,
+      LocalStackAllocator localStackAllocator) {
     assert invoke.isInvokeVirtual();
     // TODO(b/247076137): Support two coordinates (array element VarHandle).
     assert (coordinates == 1 || coordinates == 2)
@@ -415,10 +461,16 @@
       assert isPrimitiveThatIsNotBoxed(argumentType) || argumentType == factory.objectType;
     }
     DexString name = invoke.getMethod().getName();
+    boolean popReturnValue = false;
     DexType returnType =
         factory.polymorphicMethods.varHandleCompareAndSetMethodNames.contains(name)
             ? proto.returnType
             : objectOrPrimitiveReturnType(proto.returnType);
+    if (returnType.isVoidType()
+        && factory.polymorphicMethods.varHandleMethodsWithPolymorphicReturnType.contains(name)) {
+      returnType = factory.objectType;
+      popReturnValue = true;
+    }
 
     if (coordinates == 1) {
       newParameters.add(factory.objectType);
@@ -462,11 +514,13 @@
         if (!lastArgument) {
           if (hasWideArgument) {
             local = freshLocalProvider.getFreshLocal(2);
+            localStackAllocator.allocateLocalStack(1);
             builder.add(new CfStore(ValueType.fromDexType(proto.parameters.get(i + 1)), local));
           } else {
             builder.add(new CfStackInstruction(Opcode.Swap));
           }
         }
+        localStackAllocator.allocateLocalStack(1);
         builder.add(
             new CfInvoke(
                 Opcodes.INVOKESTATIC,
@@ -485,7 +539,7 @@
       }
     }
     assert newParameters.size() == proto.parameters.size();
-    if (proto.returnType != returnType) {
+    if (proto.returnType != returnType && proto.returnType != factory.voidType) {
       if (proto.returnType.isPrimitiveType()) {
         builder.add(new CfConstClass(factory.getBoxedForPrimitiveType(proto.returnType)));
       } else {
@@ -496,8 +550,12 @@
     DexProto newProto = factory.createProto(returnType, newParameters);
     DexMethod newMethod = factory.createMethod(factory.varHandleType, newProto, name);
     builder.add(new CfInvoke(Opcodes.INVOKEVIRTUAL, newMethod, false));
-    if (proto.returnType.isPrimitiveType() && !newProto.returnType.isPrimitiveType()) {
+    if (popReturnValue) {
+      localStackAllocator.allocateLocalStack(1);
+      builder.add(new CfStackInstruction(Opcode.Pop));
+    } else if (proto.returnType.isPrimitiveType() && !newProto.returnType.isPrimitiveType()) {
       assert newProto.returnType == factory.objectType;
+      localStackAllocator.allocateLocalStack(2);
       builder.add(new CfCheckCast(factory.getBoxedForPrimitiveType(proto.returnType)));
       builder.add(
           new CfInvoke(
@@ -505,6 +563,7 @@
     } else if (proto.returnType.isClassType()
         && proto.returnType != factory.objectType
         && proto.returnType != factory.voidType) {
+      localStackAllocator.allocateLocalStack(1);
       builder.add(new CfCheckCast(proto.returnType));
     }
     return builder.build();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaringMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaringMethods.java
index c2673ba..f5dc15e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaringMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaringMethods.java
@@ -113,11 +113,6 @@
                 .setAccessFlags(FieldAccessFlags.createPublicFinalSynthetic())
                 .disableAndroidApiLevelCheck()
                 .build()));
-    DexMethod toIntIfPossible =
-        factory.createMethod(
-            builder.getType(),
-            factory.createProto(factory.intType, factory.objectType, factory.booleanType),
-            factory.createString("toIntIfPossible"));
     DexMethod compareAndSet =
         factory.createMethod(
             builder.getType(),
@@ -133,20 +128,6 @@
                 factory.intType,
                 factory.createType(factory.createString("Ljava/lang/Class;"))),
             factory.createString("get"));
-    DexMethod setArrayInt =
-        factory.createMethod(
-            builder.getType(),
-            factory.createProto(
-                factory.voidType,
-                factory.createType(factory.createString("[I")),
-                factory.intType,
-                factory.intType),
-            factory.createString("set"));
-    DexMethod setLong =
-        factory.createMethod(
-            builder.getType(),
-            factory.createProto(factory.voidType, factory.objectType, factory.longType),
-            factory.createString("set"));
     DexMethod boxIntIfPossible =
         factory.createMethod(
             builder.getType(),
@@ -170,22 +151,193 @@
                 factory.intType,
                 factory.longType),
             factory.createString("set"));
+    DexMethod setVolatileArray =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.voidType, factory.objectType, factory.intType, factory.objectType),
+            factory.createString("setVolatile"));
     DexMethod getInt =
         factory.createMethod(
             builder.getType(),
             factory.createProto(factory.intType, factory.objectType),
             factory.createString("get"));
+    DexMethod setVolatileLong =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.voidType, factory.objectType, factory.longType),
+            factory.createString("setVolatile"));
+    DexMethod getLong =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.longType, factory.objectType),
+            factory.createString("get"));
+    DexMethod setVolatileInt =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.voidType, factory.objectType, factory.intType),
+            factory.createString("setVolatile"));
+    DexMethod getVolatileLong =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.longType, factory.objectType),
+            factory.createString("getVolatile"));
+    DexMethod get =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.objectType, factory.objectType),
+            factory.createString("get"));
+    DexMethod getVolatileInBox =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.objectType,
+                factory.objectType,
+                factory.createType(factory.createString("Ljava/lang/Class;"))),
+            factory.createString("getVolatile"));
+    DexMethod compareAndSetArrayInt =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.booleanType,
+                factory.createType(factory.createString("[I")),
+                factory.intType,
+                factory.intType,
+                factory.intType),
+            factory.createString("compareAndSet"));
+    DexMethod setInt =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.voidType, factory.objectType, factory.intType),
+            factory.createString("set"));
+    DexMethod weakCompareAndSet =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.booleanType, factory.objectType, factory.objectType, factory.objectType),
+            factory.createString("weakCompareAndSet"));
+    DexMethod arrayRequiringNativeSupport =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.createType(factory.createString("Ljava/lang/String;"))),
+            factory.createString("arrayRequiringNativeSupport"));
+    DexMethod boxLongIfPossible =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.objectType,
+                factory.longType,
+                factory.createType(factory.createString("Ljava/lang/Class;"))),
+            factory.createString("boxLongIfPossible"));
+    DexMethod toLongIfPossible =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.longType, factory.objectType, factory.booleanType),
+            factory.createString("toLongIfPossible"));
+    DexMethod set =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.voidType, factory.objectType, factory.objectType),
+            factory.createString("set"));
+    DexMethod getArrayInt =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.intType, factory.createType(factory.createString("[I")), factory.intType),
+            factory.createString("get"));
+    DexMethod weakCompareAndSetArray =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.booleanType,
+                factory.objectType,
+                factory.intType,
+                factory.objectType,
+                factory.objectType),
+            factory.createString("weakCompareAndSet"));
+    DexMethod setArray =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.voidType, factory.objectType, factory.intType, factory.objectType),
+            factory.createString("set"));
+    DexMethod compareAndSetInt =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.booleanType, factory.objectType, factory.intType, factory.intType),
+            factory.createString("compareAndSet"));
+    DexMethod weakCompareAndSetLong =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.booleanType, factory.objectType, factory.longType, factory.longType),
+            factory.createString("weakCompareAndSet"));
+    DexMethod getVolatileArrayInBox =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.objectType,
+                factory.objectType,
+                factory.intType,
+                factory.createType(factory.createString("Ljava/lang/Class;"))),
+            factory.createString("getVolatile"));
+    DexMethod getVolatileArrayLong =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.longType, factory.createType(factory.createString("[J")), factory.intType),
+            factory.createString("getVolatile"));
+    DexMethod getVolatileArrayInt =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.intType, factory.createType(factory.createString("[I")), factory.intType),
+            factory.createString("getVolatile"));
+    DexMethod toIntIfPossible =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.intType, factory.objectType, factory.booleanType),
+            factory.createString("toIntIfPossible"));
+    DexMethod setReleaseLong =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.voidType, factory.objectType, factory.longType),
+            factory.createString("setRelease"));
+    DexMethod setVolatileArrayInt =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.voidType,
+                factory.createType(factory.createString("[I")),
+                factory.intType,
+                factory.intType),
+            factory.createString("setVolatile"));
+    DexMethod setArrayInt =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.voidType,
+                factory.createType(factory.createString("[I")),
+                factory.intType,
+                factory.intType),
+            factory.createString("set"));
+    DexMethod setLong =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.voidType, factory.objectType, factory.longType),
+            factory.createString("set"));
     DexMethod getArrayLong =
         factory.createMethod(
             builder.getType(),
             factory.createProto(
                 factory.longType, factory.createType(factory.createString("[J")), factory.intType),
             factory.createString("get"));
-    DexMethod getLong =
+    DexMethod getVolatileInt =
         factory.createMethod(
             builder.getType(),
-            factory.createProto(factory.longType, factory.objectType),
-            factory.createString("get"));
+            factory.createProto(factory.intType, factory.objectType),
+            factory.createString("getVolatile"));
     DexMethod compareAndSetArrayLong =
         factory.createMethod(
             builder.getType(),
@@ -204,32 +356,60 @@
                 factory.objectType,
                 factory.createType(factory.createString("Ljava/lang/Class;"))),
             factory.createString("get"));
-    DexMethod get =
+    DexMethod setReleaseInt =
         factory.createMethod(
             builder.getType(),
-            factory.createProto(factory.objectType, factory.objectType),
-            factory.createString("get"));
-    DexMethod compareAndSetArrayInt =
+            factory.createProto(factory.voidType, factory.objectType, factory.intType),
+            factory.createString("setRelease"));
+    DexMethod getVolatileArray =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.objectType, factory.objectType, factory.intType),
+            factory.createString("getVolatile"));
+    DexMethod setReleaseArray =
         factory.createMethod(
             builder.getType(),
             factory.createProto(
-                factory.booleanType,
+                factory.voidType, factory.objectType, factory.intType, factory.objectType),
+            factory.createString("setRelease"));
+    DexMethod setRelease =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.voidType, factory.objectType, factory.objectType),
+            factory.createString("setRelease"));
+    DexMethod setReleaseArrayLong =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.voidType,
+                factory.createType(factory.createString("[J")),
+                factory.intType,
+                factory.longType),
+            factory.createString("setRelease"));
+    DexMethod setVolatileArrayLong =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.voidType,
+                factory.createType(factory.createString("[J")),
+                factory.intType,
+                factory.longType),
+            factory.createString("setVolatile"));
+    DexMethod setReleaseArrayInt =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.voidType,
                 factory.createType(factory.createString("[I")),
                 factory.intType,
-                factory.intType,
                 factory.intType),
-            factory.createString("compareAndSet"));
+            factory.createString("setRelease"));
     DexMethod constructor_1 =
         factory.createMethod(
             builder.getType(),
             factory.createProto(
                 factory.voidType, factory.createType(factory.createString("Ljava/lang/Class;"))),
             factory.createString("<init>"));
-    DexMethod setInt =
-        factory.createMethod(
-            builder.getType(),
-            factory.createProto(factory.voidType, factory.objectType, factory.intType),
-            factory.createString("set"));
     DexMethod constructor_3 =
         factory.createMethod(
             builder.getType(),
@@ -239,53 +419,48 @@
                 factory.createType(factory.createString("Ljava/lang/String;")),
                 factory.createType(factory.createString("Ljava/lang/Class;"))),
             factory.createString("<init>"));
-    DexMethod arrayRequiringNativeSupport =
+    DexMethod getVolatile =
         factory.createMethod(
             builder.getType(),
-            factory.createProto(factory.createType(factory.createString("Ljava/lang/String;"))),
-            factory.createString("arrayRequiringNativeSupport"));
-    DexMethod boxLongIfPossible =
+            factory.createProto(factory.objectType, factory.objectType),
+            factory.createString("getVolatile"));
+    DexMethod weakCompareAndSetArrayLong =
         factory.createMethod(
             builder.getType(),
             factory.createProto(
-                factory.objectType,
+                factory.booleanType,
+                factory.createType(factory.createString("[J")),
+                factory.intType,
                 factory.longType,
-                factory.createType(factory.createString("Ljava/lang/Class;"))),
-            factory.createString("boxLongIfPossible"));
+                factory.longType),
+            factory.createString("weakCompareAndSet"));
+    DexMethod setVolatile =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(factory.voidType, factory.objectType, factory.objectType),
+            factory.createString("setVolatile"));
+    DexMethod weakCompareAndSetArrayInt =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.booleanType,
+                factory.createType(factory.createString("[I")),
+                factory.intType,
+                factory.intType,
+                factory.intType),
+            factory.createString("weakCompareAndSet"));
     DexMethod compareAndSetLong =
         factory.createMethod(
             builder.getType(),
             factory.createProto(
                 factory.booleanType, factory.objectType, factory.longType, factory.longType),
             factory.createString("compareAndSet"));
-    DexMethod toLongIfPossible =
-        factory.createMethod(
-            builder.getType(),
-            factory.createProto(factory.longType, factory.objectType, factory.booleanType),
-            factory.createString("toLongIfPossible"));
-    DexMethod set =
-        factory.createMethod(
-            builder.getType(),
-            factory.createProto(factory.voidType, factory.objectType, factory.objectType),
-            factory.createString("set"));
-    DexMethod getArrayInt =
-        factory.createMethod(
-            builder.getType(),
-            factory.createProto(
-                factory.intType, factory.createType(factory.createString("[I")), factory.intType),
-            factory.createString("get"));
-    DexMethod setArray =
-        factory.createMethod(
-            builder.getType(),
-            factory.createProto(
-                factory.voidType, factory.objectType, factory.intType, factory.objectType),
-            factory.createString("set"));
-    DexMethod compareAndSetInt =
+    DexMethod weakCompareAndSetInt =
         factory.createMethod(
             builder.getType(),
             factory.createProto(
                 factory.booleanType, factory.objectType, factory.intType, factory.intType),
-            factory.createString("compareAndSet"));
+            factory.createString("weakCompareAndSet"));
     DexMethod compareAndSetArray =
         factory.createMethod(
             builder.getType(),
@@ -322,14 +497,6 @@
     builder.setVirtualMethods(
         ImmutableList.of(
             DexEncodedMethod.syntheticBuilder()
-                .setMethod(toIntIfPossible)
-                .setAccessFlags(
-                    MethodAccessFlags.fromSharedAccessFlags(
-                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
-                .setCode(DesugarVarHandle_toIntIfPossible(factory, toIntIfPossible))
-                .disableAndroidApiLevelCheck()
-                .build(),
-            DexEncodedMethod.syntheticBuilder()
                 .setMethod(compareAndSet)
                 .setAccessFlags(
                     MethodAccessFlags.fromSharedAccessFlags(
@@ -346,22 +513,6 @@
                 .disableAndroidApiLevelCheck()
                 .build(),
             DexEncodedMethod.syntheticBuilder()
-                .setMethod(setArrayInt)
-                .setAccessFlags(
-                    MethodAccessFlags.fromSharedAccessFlags(
-                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
-                .setCode(DesugarVarHandle_setArrayInt(factory, setArrayInt))
-                .disableAndroidApiLevelCheck()
-                .build(),
-            DexEncodedMethod.syntheticBuilder()
-                .setMethod(setLong)
-                .setAccessFlags(
-                    MethodAccessFlags.fromSharedAccessFlags(
-                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
-                .setCode(DesugarVarHandle_setLong(factory, setLong))
-                .disableAndroidApiLevelCheck()
-                .build(),
-            DexEncodedMethod.syntheticBuilder()
                 .setMethod(boxIntIfPossible)
                 .setAccessFlags(
                     MethodAccessFlags.fromSharedAccessFlags(
@@ -388,6 +539,14 @@
                 .disableAndroidApiLevelCheck()
                 .build(),
             DexEncodedMethod.syntheticBuilder()
+                .setMethod(setVolatileArray)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_setVolatileArray(factory, setVolatileArray))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
                 .setMethod(getInt)
                 .setAccessFlags(
                     MethodAccessFlags.fromSharedAccessFlags(
@@ -396,11 +555,11 @@
                 .disableAndroidApiLevelCheck()
                 .build(),
             DexEncodedMethod.syntheticBuilder()
-                .setMethod(getArrayLong)
+                .setMethod(setVolatileLong)
                 .setAccessFlags(
                     MethodAccessFlags.fromSharedAccessFlags(
                         Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
-                .setCode(DesugarVarHandle_getArrayLong(factory, getArrayLong))
+                .setCode(DesugarVarHandle_setVolatileLong(factory, setVolatileLong))
                 .disableAndroidApiLevelCheck()
                 .build(),
             DexEncodedMethod.syntheticBuilder()
@@ -412,19 +571,19 @@
                 .disableAndroidApiLevelCheck()
                 .build(),
             DexEncodedMethod.syntheticBuilder()
-                .setMethod(compareAndSetArrayLong)
+                .setMethod(setVolatileInt)
                 .setAccessFlags(
                     MethodAccessFlags.fromSharedAccessFlags(
                         Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
-                .setCode(DesugarVarHandle_compareAndSetArrayLong(factory, compareAndSetArrayLong))
+                .setCode(DesugarVarHandle_setVolatileInt(factory, setVolatileInt))
                 .disableAndroidApiLevelCheck()
                 .build(),
             DexEncodedMethod.syntheticBuilder()
-                .setMethod(getInBox)
+                .setMethod(getVolatileLong)
                 .setAccessFlags(
                     MethodAccessFlags.fromSharedAccessFlags(
                         Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
-                .setCode(DesugarVarHandle_getInBox(factory, getInBox))
+                .setCode(DesugarVarHandle_getVolatileLong(factory, getVolatileLong))
                 .disableAndroidApiLevelCheck()
                 .build(),
             DexEncodedMethod.syntheticBuilder()
@@ -436,6 +595,14 @@
                 .disableAndroidApiLevelCheck()
                 .build(),
             DexEncodedMethod.syntheticBuilder()
+                .setMethod(getVolatileInBox)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_getVolatileInBox(factory, getVolatileInBox))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
                 .setMethod(compareAndSetArrayInt)
                 .setAccessFlags(
                     MethodAccessFlags.fromSharedAccessFlags(
@@ -452,6 +619,14 @@
                 .disableAndroidApiLevelCheck()
                 .build(),
             DexEncodedMethod.syntheticBuilder()
+                .setMethod(weakCompareAndSet)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_weakCompareAndSet(factory, weakCompareAndSet))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
                 .setMethod(arrayRequiringNativeSupport)
                 .setAccessFlags(
                     MethodAccessFlags.fromSharedAccessFlags(
@@ -470,14 +645,6 @@
                 .disableAndroidApiLevelCheck()
                 .build(),
             DexEncodedMethod.syntheticBuilder()
-                .setMethod(compareAndSetLong)
-                .setAccessFlags(
-                    MethodAccessFlags.fromSharedAccessFlags(
-                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
-                .setCode(DesugarVarHandle_compareAndSetLong(factory, compareAndSetLong))
-                .disableAndroidApiLevelCheck()
-                .build(),
-            DexEncodedMethod.syntheticBuilder()
                 .setMethod(toLongIfPossible)
                 .setAccessFlags(
                     MethodAccessFlags.fromSharedAccessFlags(
@@ -502,6 +669,14 @@
                 .disableAndroidApiLevelCheck()
                 .build(),
             DexEncodedMethod.syntheticBuilder()
+                .setMethod(weakCompareAndSetArray)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_weakCompareAndSetArray(factory, weakCompareAndSetArray))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
                 .setMethod(setArray)
                 .setAccessFlags(
                     MethodAccessFlags.fromSharedAccessFlags(
@@ -518,6 +693,217 @@
                 .disableAndroidApiLevelCheck()
                 .build(),
             DexEncodedMethod.syntheticBuilder()
+                .setMethod(weakCompareAndSetLong)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_weakCompareAndSetLong(factory, weakCompareAndSetLong))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(getVolatileArrayInBox)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_getVolatileArrayInBox(factory, getVolatileArrayInBox))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(getVolatileArrayLong)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_getVolatileArrayLong(factory, getVolatileArrayLong))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(getVolatileArrayInt)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_getVolatileArrayInt(factory, getVolatileArrayInt))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(toIntIfPossible)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_toIntIfPossible(factory, toIntIfPossible))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(setReleaseLong)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_setReleaseLong(factory, setReleaseLong))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(setVolatileArrayInt)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_setVolatileArrayInt(factory, setVolatileArrayInt))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(setArrayInt)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_setArrayInt(factory, setArrayInt))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(setLong)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_setLong(factory, setLong))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(getArrayLong)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_getArrayLong(factory, getArrayLong))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(getVolatileInt)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_getVolatileInt(factory, getVolatileInt))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(compareAndSetArrayLong)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_compareAndSetArrayLong(factory, compareAndSetArrayLong))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(getInBox)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_getInBox(factory, getInBox))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(setReleaseInt)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_setReleaseInt(factory, setReleaseInt))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(getVolatileArray)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_getVolatileArray(factory, getVolatileArray))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(setReleaseArray)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_setReleaseArray(factory, setReleaseArray))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(setRelease)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_setRelease(factory, setRelease))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(setReleaseArrayLong)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_setReleaseArrayLong(factory, setReleaseArrayLong))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(setVolatileArrayLong)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_setVolatileArrayLong(factory, setVolatileArrayLong))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(setReleaseArrayInt)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_setReleaseArrayInt(factory, setReleaseArrayInt))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(getVolatile)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_getVolatile(factory, getVolatile))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(weakCompareAndSetArrayLong)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(
+                    DesugarVarHandle_weakCompareAndSetArrayLong(
+                        factory, weakCompareAndSetArrayLong))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(setVolatile)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_setVolatile(factory, setVolatile))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(weakCompareAndSetArrayInt)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(
+                    DesugarVarHandle_weakCompareAndSetArrayInt(factory, weakCompareAndSetArrayInt))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(compareAndSetLong)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_compareAndSetLong(factory, compareAndSetLong))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(weakCompareAndSetInt)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarVarHandle_weakCompareAndSetInt(factory, weakCompareAndSetInt))
+                .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
                 .setMethod(compareAndSetArray)
                 .setAccessFlags(
                     MethodAccessFlags.fromSharedAccessFlags(
@@ -547,6 +933,13 @@
                 factory.createType(factory.createString("Ljava/lang/String;")),
                 factory.createType(factory.createString("Ljava/lang/Class;"))),
             factory.createString("findVarHandle"));
+    DexMethod toPrivateLookupIn =
+        factory.createMethod(
+            builder.getType(),
+            factory.createProto(
+                factory.createType(factory.createString("Ljava/lang/invoke/MethodHandles$Lookup;")),
+                factory.createType(factory.createString("Ljava/lang/Class;"))),
+            factory.createString("toPrivateLookupIn"));
     DexMethod constructor_0 =
         factory.createMethod(
             builder.getType(),
@@ -571,6 +964,14 @@
                         Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
                 .setCode(DesugarMethodHandlesLookup_findVarHandle(factory, findVarHandle))
                 .disableAndroidApiLevelCheck()
+                .build(),
+            DexEncodedMethod.syntheticBuilder()
+                .setMethod(toPrivateLookupIn)
+                .setAccessFlags(
+                    MethodAccessFlags.fromSharedAccessFlags(
+                        Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+                .setCode(DesugarMethodHandlesLookup_toPrivateLookupIn(factory, toPrivateLookupIn))
+                .disableAndroidApiLevelCheck()
                 .build()));
   }
 
@@ -627,6 +1028,20 @@
         ImmutableList.of());
   }
 
+  public static CfCode DesugarMethodHandlesLookup_toPrivateLookupIn(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        1,
+        2,
+        ImmutableList.of(
+            label0, new CfLoad(ValueType.OBJECT, 0), new CfReturn(ValueType.OBJECT), label1),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
   public static CfCode DesugarVarHandle_constructor_1(DexItemFactory factory, DexMethod method) {
     CfLabel label0 = new CfLabel();
     CfLabel label1 = new CfLabel();
@@ -3641,6 +4056,1227 @@
         ImmutableList.of());
   }
 
+  public static CfCode DesugarVarHandle_getVolatile(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        4,
+        2,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.longType),
+                    factory.createString("getIntVolatile")),
+                false),
+            new CfInvoke(
+                184,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.createProto(factory.createType("Ljava/lang/Integer;"), factory.intType),
+                    factory.createString("valueOf")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.longType),
+                    factory.createString("getLongVolatile")),
+                false),
+            new CfInvoke(
+                184,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.createProto(factory.createType("Ljava/lang/Long;"), factory.longType),
+                    factory.createString("valueOf")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.objectType, factory.objectType, factory.longType),
+                    factory.createString("getObjectVolatile")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label5),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_getVolatileArray(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    CfLabel label7 = new CfLabel();
+    CfLabel label8 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        5,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.classType,
+                    factory.createProto(factory.booleanType),
+                    factory.createString("isArray")),
+                false),
+            new CfIf(If.Type.EQ, ValueType.INT, label1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.objectType,
+                    factory.createProto(factory.classType),
+                    factory.createString("getClass")),
+                false),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType()
+                    })),
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 3),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label5),
+            label4,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.longType),
+                    factory.createString("getIntVolatile")),
+                false),
+            new CfInvoke(
+                184,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.createProto(factory.createType("Ljava/lang/Integer;"), factory.intType),
+                    factory.createString("valueOf")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label5,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label7),
+            label6,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.longType),
+                    factory.createString("getLongVolatile")),
+                false),
+            new CfNumberConversion(NumericType.LONG, NumericType.INT),
+            new CfInvoke(
+                184,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.createProto(factory.createType("Ljava/lang/Integer;"), factory.intType),
+                    factory.createString("valueOf")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label7,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.objectType, factory.objectType, factory.longType),
+                    factory.createString("getObjectVolatile")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label8),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_getVolatileArrayInBox(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    CfLabel label7 = new CfLabel();
+    CfLabel label8 = new CfLabel();
+    CfLabel label9 = new CfLabel();
+    CfLabel label10 = new CfLabel();
+    CfLabel label11 = new CfLabel();
+    CfLabel label12 = new CfLabel();
+    CfLabel label13 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        7,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.classType,
+                    factory.createProto(factory.booleanType),
+                    factory.createString("isArray")),
+                false),
+            new CfIf(If.Type.EQ, ValueType.INT, label1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.objectType,
+                    factory.createProto(factory.classType),
+                    factory.createString("getClass")),
+                false),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.classType)
+                    })),
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.classType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label5),
+            label4,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 4),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.longType),
+                    factory.createString("getIntVolatile")),
+                false),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.objectType, factory.intType, factory.classType),
+                    factory.createString("boxIntIfPossible")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label5,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.classType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label7),
+            label6,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 4),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.longType),
+                    factory.createString("getLongVolatile")),
+                false),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.objectType, factory.longType, factory.classType),
+                    factory.createString("boxLongIfPossible")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label7,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.classType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 4),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.objectType, factory.objectType, factory.longType),
+                    factory.createString("getObjectVolatile")),
+                false),
+            new CfStore(ValueType.OBJECT, 6),
+            label8,
+            new CfLoad(ValueType.OBJECT, 6),
+            new CfInstanceOf(factory.createType("Ljava/lang/Integer;")),
+            new CfIf(If.Type.EQ, ValueType.INT, label10),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfConstClass(factory.createType("Ljava/lang/Integer;")),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label10),
+            label9,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 6),
+            new CfCheckCast(factory.createType("Ljava/lang/Integer;")),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.createProto(factory.intType),
+                    factory.createString("intValue")),
+                false),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.objectType, factory.intType, factory.classType),
+                    factory.createString("boxIntIfPossible")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label10,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5, 6},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.classType),
+                      FrameType.longType(),
+                      FrameType.longHighType(),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 6),
+            new CfInstanceOf(factory.createType("Ljava/lang/Long;")),
+            new CfIf(If.Type.EQ, ValueType.INT, label12),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfConstClass(factory.createType("Ljava/lang/Long;")),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label12),
+            label11,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 6),
+            new CfCheckCast(factory.createType("Ljava/lang/Long;")),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.createProto(factory.longType),
+                    factory.createString("longValue")),
+                false),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.objectType, factory.longType, factory.classType),
+                    factory.createString("boxLongIfPossible")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label12,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5, 6},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.classType),
+                      FrameType.longType(),
+                      FrameType.longHighType(),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 6),
+            new CfReturn(ValueType.OBJECT),
+            label13),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_getVolatileArrayInt(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        5,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.intArrayType),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.intArrayType),
+                      FrameType.intType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 3),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.longType),
+                    factory.createString("getIntVolatile")),
+                false),
+            new CfReturn(ValueType.INT),
+            label4),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_getVolatileArrayLong(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        5,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.longArrayType),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.longArrayType),
+                      FrameType.intType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 3),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.longType),
+                    factory.createString("getLongVolatile")),
+                false),
+            new CfReturn(ValueType.LONG),
+            label4),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_getVolatileInBox(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        5,
+        3,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.longType),
+                    factory.createString("getIntVolatile")),
+                false),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.objectType, factory.intType, factory.classType),
+                    factory.createString("boxIntIfPossible")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.classType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.longType),
+                    factory.createString("getLongVolatile")),
+                false),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.objectType, factory.longType, factory.classType),
+                    factory.createString("boxLongIfPossible")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.classType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.objectType, factory.objectType, factory.longType),
+                    factory.createString("getObjectVolatile")),
+                false),
+            new CfReturn(ValueType.OBJECT),
+            label5),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_getVolatileInt(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        5,
+        2,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.longType),
+                    factory.createString("getIntVolatile")),
+                false),
+            new CfReturn(ValueType.INT),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.createType("Ljava/lang/RuntimeException;")),
+                    factory.createString("desugarWrongMethodTypeException")),
+                false),
+            new CfThrow(),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.objectType, factory.objectType, factory.longType),
+                    factory.createString("getObjectVolatile")),
+                false),
+            new CfConstNumber(1, ValueType.INT),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.booleanType),
+                    factory.createString("toIntIfPossible")),
+                false),
+            new CfReturn(ValueType.INT),
+            label5),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_getVolatileLong(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        5,
+        2,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.longType),
+                    factory.createString("getLongVolatile")),
+                false),
+            new CfReturn(ValueType.LONG),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.longType),
+                    factory.createString("getIntVolatile")),
+                false),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfReturn(ValueType.LONG),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(factory.objectType, factory.objectType, factory.longType),
+                    factory.createString("getObjectVolatile")),
+                false),
+            new CfConstNumber(1, ValueType.INT),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.booleanType),
+                    factory.createString("toLongIfPossible")),
+                false),
+            new CfReturn(ValueType.LONG),
+            label5),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
   public static CfCode DesugarVarHandle_set(DexItemFactory factory, DexMethod method) {
     CfLabel label0 = new CfLabel();
     CfLabel label1 = new CfLabel();
@@ -4460,6 +6096,1648 @@
         ImmutableList.of());
   }
 
+  public static CfCode DesugarVarHandle_setRelease(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        5,
+        3,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfConstNumber(0, ValueType.INT),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.booleanType),
+                    factory.createString("toIntIfPossible")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.voidType, factory.objectType, factory.intType),
+                    factory.createString("setRelease")),
+                false),
+            new CfGoto(label5),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfConstNumber(0, ValueType.INT),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.booleanType),
+                    factory.createString("toLongIfPossible")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.voidType, factory.objectType, factory.longType),
+                    factory.createString("setRelease")),
+                false),
+            new CfGoto(label5),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.objectType),
+                    factory.createString("putOrderedObject")),
+                false),
+            label5,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfReturnVoid(),
+            label6),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_setReleaseArray(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    CfLabel label7 = new CfLabel();
+    CfLabel label8 = new CfLabel();
+    CfLabel label9 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        7,
+        6,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.classType,
+                    factory.createProto(factory.booleanType),
+                    factory.createString("isArray")),
+                false),
+            new CfIf(If.Type.EQ, ValueType.INT, label1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.objectType,
+                    factory.createProto(factory.classType),
+                    factory.createString("getClass")),
+                false),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.intArrayType),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label5),
+            label4,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 4),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfConstNumber(0, ValueType.INT),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.booleanType),
+                    factory.createString("toIntIfPossible")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.intType),
+                    factory.createString("putOrderedInt")),
+                false),
+            new CfGoto(label8),
+            label5,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.longArrayType),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label7),
+            label6,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 4),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfConstNumber(0, ValueType.INT),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.booleanType),
+                    factory.createString("toLongIfPossible")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.longType),
+                    factory.createString("putOrderedLong")),
+                false),
+            new CfGoto(label8),
+            label7,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 4),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.objectType),
+                    factory.createString("putOrderedObject")),
+                false),
+            label8,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfReturnVoid(),
+            label9),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_setReleaseArrayInt(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        6,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.intArrayType),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.intArrayType),
+                      FrameType.intType(),
+                      FrameType.intType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 4),
+            new CfLoad(ValueType.INT, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.intType),
+                    factory.createString("putOrderedInt")),
+                false),
+            label4,
+            new CfReturnVoid(),
+            label5),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_setReleaseArrayLong(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        7,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.longArrayType),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.longArrayType),
+                      FrameType.intType(),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 5),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 5),
+            new CfLoad(ValueType.LONG, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.longType),
+                    factory.createString("putOrderedLong")),
+                false),
+            label4,
+            new CfReturnVoid(),
+            label5),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_setReleaseInt(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        3,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.intType),
+                    factory.createString("putOrderedInt")),
+                false),
+            new CfGoto(label5),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.longType),
+                    factory.createString("putOrderedLong")),
+                false),
+            new CfGoto(label5),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.INT, 2),
+            new CfInvoke(
+                184,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.createProto(factory.createType("Ljava/lang/Integer;"), factory.intType),
+                    factory.createString("valueOf")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.voidType, factory.objectType, factory.objectType),
+                    factory.createString("setRelease")),
+                false),
+            label5,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType()
+                    })),
+            new CfReturnVoid(),
+            label6),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_setReleaseLong(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        4,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.LONG, 2),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.longType),
+                    factory.createString("putOrderedLong")),
+                false),
+            new CfGoto(label5),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.createType("Ljava/lang/RuntimeException;")),
+                    factory.createString("desugarWrongMethodTypeException")),
+                false),
+            new CfThrow(),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.LONG, 2),
+            new CfInvoke(
+                184,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.createProto(factory.createType("Ljava/lang/Long;"), factory.longType),
+                    factory.createString("valueOf")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.objectType),
+                    factory.createString("putOrderedObject")),
+                false),
+            label5,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfReturnVoid(),
+            label6),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_setVolatile(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        5,
+        3,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfConstNumber(0, ValueType.INT),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.booleanType),
+                    factory.createString("toIntIfPossible")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.voidType, factory.objectType, factory.intType),
+                    factory.createString("setVolatile")),
+                false),
+            new CfGoto(label5),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfConstNumber(0, ValueType.INT),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.booleanType),
+                    factory.createString("toLongIfPossible")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.voidType, factory.objectType, factory.longType),
+                    factory.createString("setVolatile")),
+                false),
+            new CfGoto(label5),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.objectType),
+                    factory.createString("putObjectVolatile")),
+                false),
+            label5,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfReturnVoid(),
+            label6),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_setVolatileArray(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    CfLabel label7 = new CfLabel();
+    CfLabel label8 = new CfLabel();
+    CfLabel label9 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        7,
+        6,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.classType,
+                    factory.createProto(factory.booleanType),
+                    factory.createString("isArray")),
+                false),
+            new CfIf(If.Type.EQ, ValueType.INT, label1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.objectType,
+                    factory.createProto(factory.classType),
+                    factory.createString("getClass")),
+                false),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.intArrayType),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label5),
+            label4,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 4),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfConstNumber(0, ValueType.INT),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.booleanType),
+                    factory.createString("toIntIfPossible")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.intType),
+                    factory.createString("putIntVolatile")),
+                false),
+            new CfGoto(label8),
+            label5,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.longArrayType),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label7),
+            label6,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 4),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfConstNumber(0, ValueType.INT),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.booleanType),
+                    factory.createString("toLongIfPossible")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.longType),
+                    factory.createString("putLongVolatile")),
+                false),
+            new CfGoto(label8),
+            label7,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 4),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.objectType),
+                    factory.createString("putObjectVolatile")),
+                false),
+            label8,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfReturnVoid(),
+            label9),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_setVolatileArrayInt(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        6,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.intArrayType),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.intArrayType),
+                      FrameType.intType(),
+                      FrameType.intType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 4),
+            new CfLoad(ValueType.INT, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.intType),
+                    factory.createString("putIntVolatile")),
+                false),
+            label4,
+            new CfReturnVoid(),
+            label5),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_setVolatileArrayLong(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        7,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.longArrayType),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.longArrayType),
+                      FrameType.intType(),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 5),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 5),
+            new CfLoad(ValueType.LONG, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.longType),
+                    factory.createString("putLongVolatile")),
+                false),
+            label4,
+            new CfReturnVoid(),
+            label5),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_setVolatileInt(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        3,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.intType),
+                    factory.createString("putIntVolatile")),
+                false),
+            new CfGoto(label5),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.longType),
+                    factory.createString("putLongVolatile")),
+                false),
+            new CfGoto(label5),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.INT, 2),
+            new CfInvoke(
+                184,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.createProto(factory.createType("Ljava/lang/Integer;"), factory.intType),
+                    factory.createString("valueOf")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.voidType, factory.objectType, factory.objectType),
+                    factory.createString("setVolatile")),
+                false),
+            label5,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType()
+                    })),
+            new CfReturnVoid(),
+            label6),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_setVolatileLong(DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        4,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.LONG, 2),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.longType),
+                    factory.createString("putLongVolatile")),
+                false),
+            new CfGoto(label5),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.createType("Ljava/lang/RuntimeException;")),
+                    factory.createString("desugarWrongMethodTypeException")),
+                false),
+            new CfThrow(),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.LONG, 2),
+            new CfInvoke(
+                184,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.createProto(factory.createType("Ljava/lang/Long;"), factory.longType),
+                    factory.createString("valueOf")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.voidType, factory.objectType, factory.longType, factory.objectType),
+                    factory.createString("putObjectVolatile")),
+                false),
+            label5,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfReturnVoid(),
+            label6),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
   public static CfCode DesugarVarHandle_toIntIfPossible(DexItemFactory factory, DexMethod method) {
     CfLabel label0 = new CfLabel();
     CfLabel label1 = new CfLabel();
@@ -4663,4 +7941,903 @@
         ImmutableList.of(),
         ImmutableList.of());
   }
+
+  public static CfCode DesugarVarHandle_weakCompareAndSet(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    CfLabel label7 = new CfLabel();
+    CfLabel label8 = new CfLabel();
+    CfLabel label9 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        9,
+        4,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfConstNumber(0, ValueType.INT),
+            label2,
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.booleanType),
+                    factory.createString("toIntIfPossible")),
+                false),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfConstNumber(0, ValueType.INT),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.booleanType),
+                    factory.createString("toIntIfPossible")),
+                false),
+            label3,
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.longType,
+                        factory.intType,
+                        factory.intType),
+                    factory.createString("compareAndSwapInt")),
+                false),
+            new CfReturn(ValueType.INT),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label8),
+            label5,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfConstNumber(0, ValueType.INT),
+            label6,
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.booleanType),
+                    factory.createString("toLongIfPossible")),
+                false),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfConstNumber(0, ValueType.INT),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.booleanType),
+                    factory.createString("toLongIfPossible")),
+                false),
+            label7,
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.longType,
+                        factory.longType,
+                        factory.longType),
+                    factory.createString("compareAndSwapLong")),
+                false),
+            new CfReturn(ValueType.INT),
+            label8,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.OBJECT, 2),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.longType,
+                        factory.objectType,
+                        factory.objectType),
+                    factory.createString("compareAndSwapObject")),
+                false),
+            new CfReturn(ValueType.INT),
+            label9),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_weakCompareAndSetArray(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    CfLabel label6 = new CfLabel();
+    CfLabel label7 = new CfLabel();
+    CfLabel label8 = new CfLabel();
+    CfLabel label9 = new CfLabel();
+    CfLabel label10 = new CfLabel();
+    CfLabel label11 = new CfLabel();
+    CfLabel label12 = new CfLabel();
+    CfLabel label13 = new CfLabel();
+    CfLabel label14 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        9,
+        7,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.classType,
+                    factory.createProto(factory.booleanType),
+                    factory.createString("isArray")),
+                false),
+            new CfIf(If.Type.EQ, ValueType.INT, label1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.objectType,
+                    factory.createProto(factory.classType),
+                    factory.createString("getClass")),
+                false),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType)
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 5),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.intArrayType),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label8),
+            label4,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 5),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfConstNumber(0, ValueType.INT),
+            label5,
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.booleanType),
+                    factory.createString("toIntIfPossible")),
+                false),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 4),
+            new CfConstNumber(0, ValueType.INT),
+            label6,
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.intType, factory.objectType, factory.booleanType),
+                    factory.createString("toIntIfPossible")),
+                false),
+            label7,
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.longType,
+                        factory.intType,
+                        factory.intType),
+                    factory.createString("compareAndSwapInt")),
+                false),
+            new CfReturn(ValueType.INT),
+            label8,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5, 6},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.longArrayType),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label13),
+            label9,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 5),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfConstNumber(0, ValueType.INT),
+            label10,
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.booleanType),
+                    factory.createString("toLongIfPossible")),
+                false),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 4),
+            new CfConstNumber(0, ValueType.INT),
+            label11,
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(factory.longType, factory.objectType, factory.booleanType),
+                    factory.createString("toLongIfPossible")),
+                false),
+            label12,
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.longType,
+                        factory.longType,
+                        factory.longType),
+                    factory.createString("compareAndSwapLong")),
+                false),
+            new CfReturn(ValueType.INT),
+            label13,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5, 6},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 5),
+            new CfLoad(ValueType.OBJECT, 3),
+            new CfLoad(ValueType.OBJECT, 4),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.longType,
+                        factory.objectType,
+                        factory.objectType),
+                    factory.createString("compareAndSwapObject")),
+                false),
+            new CfReturn(ValueType.INT),
+            label14),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_weakCompareAndSetArrayInt(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        6,
+        7,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.intArrayType),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.intArrayType),
+                      FrameType.intType(),
+                      FrameType.intType(),
+                      FrameType.intType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 5),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 5),
+            new CfLoad(ValueType.INT, 3),
+            new CfLoad(ValueType.INT, 4),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.longType,
+                        factory.intType,
+                        factory.intType),
+                    factory.createString("compareAndSwapInt")),
+                false),
+            new CfReturn(ValueType.INT),
+            label4),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_weakCompareAndSetArrayLong(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        8,
+        9,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("recv"))),
+            new CfConstClass(factory.longArrayType),
+            new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label2),
+            label1,
+            new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+            new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+            new CfInvoke(
+                183,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/UnsupportedOperationException;"),
+                    factory.createProto(factory.voidType),
+                    factory.createString("<init>")),
+                false),
+            new CfThrow(),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5, 6},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.longArrayType),
+                      FrameType.intType(),
+                      FrameType.longType(),
+                      FrameType.longHighType(),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("arrayIndexScale"))),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Mul, NumericType.LONG),
+            new CfArithmeticBinop(CfArithmeticBinop.Opcode.Add, NumericType.LONG),
+            new CfStore(ValueType.LONG, 7),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 7),
+            new CfLoad(ValueType.LONG, 3),
+            new CfLoad(ValueType.LONG, 5),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.longType,
+                        factory.longType,
+                        factory.longType),
+                    factory.createString("compareAndSwapLong")),
+                false),
+            new CfReturn(ValueType.INT),
+            label4),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_weakCompareAndSetInt(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    CfLabel label4 = new CfLabel();
+    CfLabel label5 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        8,
+        4,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfLoad(ValueType.INT, 3),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.longType,
+                        factory.intType,
+                        factory.intType),
+                    factory.createString("compareAndSwapInt")),
+                false),
+            new CfReturn(ValueType.INT),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.intType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+            label3,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.INT, 2),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfLoad(ValueType.INT, 3),
+            new CfNumberConversion(NumericType.INT, NumericType.LONG),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.longType,
+                        factory.longType,
+                        factory.longType),
+                    factory.createString("compareAndSwapLong")),
+                false),
+            new CfReturn(ValueType.INT),
+            label4,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.intType(),
+                      FrameType.intType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.INT, 2),
+            new CfInvoke(
+                184,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.createProto(factory.createType("Ljava/lang/Integer;"), factory.intType),
+                    factory.createString("valueOf")),
+                false),
+            new CfLoad(ValueType.INT, 3),
+            new CfInvoke(
+                184,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Integer;"),
+                    factory.createProto(factory.createType("Ljava/lang/Integer;"), factory.intType),
+                    factory.createString("valueOf")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.objectType,
+                        factory.objectType),
+                    factory.createString("compareAndSet")),
+                false),
+            new CfReturn(ValueType.INT),
+            label5),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
+
+  public static CfCode DesugarVarHandle_weakCompareAndSetLong(
+      DexItemFactory factory, DexMethod method) {
+    CfLabel label0 = new CfLabel();
+    CfLabel label1 = new CfLabel();
+    CfLabel label2 = new CfLabel();
+    CfLabel label3 = new CfLabel();
+    return new CfCode(
+        method.holder,
+        8,
+        6,
+        ImmutableList.of(
+            label0,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.classType,
+                    factory.createString("type"))),
+            new CfStaticFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.classType,
+                    factory.createString("TYPE"))),
+            new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+            label1,
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createString("U"))),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfInstanceFieldRead(
+                factory.createField(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.longType,
+                    factory.createString("offset"))),
+            new CfLoad(ValueType.LONG, 2),
+            new CfLoad(ValueType.LONG, 4),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Lsun/misc/Unsafe;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.longType,
+                        factory.longType,
+                        factory.longType),
+                    factory.createString("compareAndSwapLong")),
+                false),
+            new CfReturn(ValueType.INT),
+            label2,
+            new CfFrame(
+                new Int2ObjectAVLTreeMap<>(
+                    new int[] {0, 1, 2, 3, 4, 5},
+                    new FrameType[] {
+                      FrameType.initializedNonNullReference(
+                          factory.createType("Ljava/lang/invoke/VarHandle;")),
+                      FrameType.initializedNonNullReference(factory.objectType),
+                      FrameType.longType(),
+                      FrameType.longHighType(),
+                      FrameType.longType(),
+                      FrameType.longHighType()
+                    })),
+            new CfLoad(ValueType.OBJECT, 0),
+            new CfLoad(ValueType.OBJECT, 1),
+            new CfLoad(ValueType.LONG, 2),
+            new CfInvoke(
+                184,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.createProto(factory.createType("Ljava/lang/Long;"), factory.longType),
+                    factory.createString("valueOf")),
+                false),
+            new CfLoad(ValueType.LONG, 4),
+            new CfInvoke(
+                184,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/Long;"),
+                    factory.createProto(factory.createType("Ljava/lang/Long;"), factory.longType),
+                    factory.createString("valueOf")),
+                false),
+            new CfInvoke(
+                182,
+                factory.createMethod(
+                    factory.createType("Ljava/lang/invoke/VarHandle;"),
+                    factory.createProto(
+                        factory.booleanType,
+                        factory.objectType,
+                        factory.objectType,
+                        factory.objectType),
+                    factory.createString("compareAndSet")),
+                false),
+            new CfReturn(ValueType.INT),
+            label3),
+        ImmutableList.of(),
+        ImmutableList.of());
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
index 2f5c0f9..98a08a1 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNamingForNameMapper.java
@@ -728,5 +728,21 @@
     public List<MappingInformation> getAdditionalMappingInformation() {
       return Collections.unmodifiableList(additionalMappingInformation);
     }
+
+    public MappedRange partitionOnMinifiedRange(Range minifiedRange) {
+      if (minifiedRange.equals(this.minifiedRange)) {
+        return this;
+      }
+      Range splitOriginalRange =
+          new Range(
+              getOriginalLineNumber(minifiedRange.from), getOriginalLineNumber(minifiedRange.to));
+      MappedRange splitMappedRange =
+          new MappedRange(minifiedRange, signature, splitOriginalRange, renamedName);
+      if (minifiedRange.to >= this.minifiedRange.to) {
+        splitMappedRange.additionalMappingInformation =
+            new ArrayList<>(this.additionalMappingInformation);
+      }
+      return splitMappedRange;
+    }
   }
 }
diff --git a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
index 35fbc04..ef5d1cf 100644
--- a/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
+++ b/src/main/java/com/android/tools/r8/naming/ComposingBuilder.java
@@ -29,6 +29,7 @@
 import com.android.tools.r8.utils.ConsumerUtils;
 import com.android.tools.r8.utils.InternalOptions;
 import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.Pair;
 import com.android.tools.r8.utils.SegmentTree;
 import com.android.tools.r8.utils.ThrowingBiFunction;
 import com.google.common.collect.Sets;
@@ -47,7 +48,6 @@
 import java.util.Objects;
 import java.util.Set;
 import java.util.TreeMap;
-import java.util.function.BiConsumer;
 import java.util.function.Consumer;
 
 public class ComposingBuilder {
@@ -547,12 +547,12 @@
       Map<String, String> inverseClassMapping =
           classNameMapper.getObfuscatedToOriginalMapping().inverse;
       for (Entry<String, MappedRangesOfName> entry : mapper.mappedRangesByRenamedName.entrySet()) {
-        MappedRangesOfName mappedRangesOfName = entry.getValue();
-        for (MappedRangesOfName rangesOfName : mappedRangesOfName.partitionOnMethodSignature()) {
+        List<MappedRangesOfName> mappedRangesOfNames =
+            entry.getValue().partitionOnMethodSignature();
+        for (MappedRangesOfName rangesOfName : mappedRangesOfNames) {
           MemberNaming memberNaming = rangesOfName.getMemberNaming(mapper);
           List<MappedRange> newMappedRanges = rangesOfName.getMappedRanges();
           RangeBuilder minified = new RangeBuilder();
-          RangeBuilder original = new RangeBuilder();
           // The new minified ranges may have ranges that range over positions that has additional
           // information, such as inlinees:
           // Existing:
@@ -576,9 +576,10 @@
           //  ...
           List<MappedRange> composedRanges = new ArrayList<>();
           ComputedOutlineInformation computedOutlineInformation = new ComputedOutlineInformation();
-          for (MappedRange mappedRange : newMappedRanges) {
+          List<List<MappedRange>> composedInlineFrames = new ArrayList<>();
+          for (int i = 0; i < newMappedRanges.size(); i++) {
+            MappedRange mappedRange = newMappedRanges.get(i);
             minified.addRange(mappedRange.minifiedRange);
-            original.addRange(mappedRange.originalRange);
             // Register mapping information that is dependent on the residual naming to allow
             // updating later on.
             registerMappingInformationFromMappedRanges(mappedRange);
@@ -603,24 +604,31 @@
                 // positions if the method is not throwing (and is not debug). Additionally, R8/PG
                 // emits `1:1:void foo() -> a` instead of `1:1:void foo():1:1 -> a`, so R8 must
                 // capture the preamble position by explicitly inserting 0 as original range.
+                int firstPositionOfOriginalRange =
+                    mappedRange.getFirstPositionOfOriginalRange(NO_RANGE_FROM);
                 Entry<Integer, List<MappedRange>> existingEntry =
-                    listSegmentTree.findEntry(original.getStartOrNoRangeFrom());
+                    listSegmentTree.findEntry(firstPositionOfOriginalRange);
+                if (existingEntry == null
+                    && firstPositionOfOriginalRange == 0
+                    && !mappedRange.originalRange.isPreamble()) {
+                  existingEntry =
+                      listSegmentTree.findEntry(mappedRange.getLastPositionOfOriginalRange());
+                }
                 // We assume that all new minified ranges for a method are rewritten in the new map
                 // such that no previous existing positions exists.
                 if (existingEntry != null) {
-                  // listSegmentTree.removeSegment(existingEntry.getKey());
                   existingMappedRanges = existingEntry.getValue();
                 } else {
                   // The original can be discarded if it no longer exists or if the method is
                   // non-throwing.
-                  if (original.hasValue()
-                      && !original.isPreamble()
+                  if (mappedRange.originalRange != null
+                      && !mappedRange.originalRange.isPreamble()
                       && !options.mappingComposeOptions().allowNonExistingOriginalRanges) {
                     throw new MappingComposeException(
                         "Could not find original starting position of '"
-                            + minified.start
+                            + mappedRange.minifiedRange.from
                             + "' which should be "
-                            + original.start);
+                            + firstPositionOfOriginalRange);
                   }
                 }
                 assert minified.hasValue();
@@ -633,9 +641,34 @@
                         : Collections.singletonList(existingMappedRange);
               }
             }
-            composedRanges.addAll(
-                composeMappedRangesForMethod(
-                    existingMappedRanges, mappedRange, computedOutlineInformation));
+            // Mapping the original ranges all the way back may cause the minified map range and the
+            // original mapped range to have different spans. We therefore maintain a collection of
+            // inline frames to add when we see the last mapped range.
+            List<List<MappedRange>> newComposedInlineFrames = new ArrayList<>();
+            if (composedInlineFrames.isEmpty()) {
+              splitOnNewMinifiedRange(
+                  composeMappedRangesForMethod(
+                      existingMappedRanges, mappedRange, computedOutlineInformation),
+                  Collections.emptyList(),
+                  newComposedInlineFrames::add);
+            } else {
+              for (List<MappedRange> composedInlineFrame : composedInlineFrames) {
+                MappedRange splitMappedRange =
+                    mappedRange.partitionOnMinifiedRange(composedInlineFrame.get(0).minifiedRange);
+                splitOnNewMinifiedRange(
+                    composeMappedRangesForMethod(
+                        existingMappedRanges, splitMappedRange, computedOutlineInformation),
+                    composedInlineFrame,
+                    newComposedInlineFrames::add);
+              }
+            }
+            composedInlineFrames = newComposedInlineFrames;
+            if (!isInlineMappedRange(newMappedRanges, i)) {
+              for (List<MappedRange> composedInlineFrame : composedInlineFrames) {
+                composedRanges.addAll(composedInlineFrame);
+              }
+              composedInlineFrames = Collections.emptyList();
+            }
           }
           MappedRange lastComposedRange = ListUtils.last(composedRanges);
           if (computedOutlineInformation.seenOutlineMappingInformation != null) {
@@ -673,12 +706,11 @@
                   .computeResidualSignature(type -> inverseClassMapping.getOrDefault(type, type))
                   .asMethodSignature();
           if (lastComposedRange.minifiedRange != null) {
-            methodsWithPosition
-                .computeIfAbsent(residualSignature, ignored -> new SegmentTree<>(false))
-                .add(
-                    minified.getStartOrNoRangeFrom(),
-                    minified.getEndOrNoRangeFrom(),
-                    composedRanges);
+            SegmentTree<List<MappedRange>> listSegmentTree =
+                methodsWithPosition.computeIfAbsent(
+                    residualSignature, ignored -> new SegmentTree<>(false));
+            listSegmentTree.add(
+                minified.getStartOrNoRangeFrom(), minified.getEndOrNoRangeFrom(), composedRanges);
           } else {
             assert composedRanges.size() == 1;
             methodsWithoutPosition.put(residualSignature, lastComposedRange);
@@ -687,6 +719,38 @@
       }
     }
 
+    private void splitOnNewMinifiedRange(
+        List<MappedRange> mappedRanges,
+        List<MappedRange> previouslyMapped,
+        Consumer<List<MappedRange>> consumer) {
+      assert !mappedRanges.isEmpty();
+      Range minifiedRange = mappedRanges.get(0).minifiedRange;
+      if (minifiedRange == null) {
+        consumer.accept(ListUtils.joinNewArrayList(previouslyMapped, mappedRanges));
+        return;
+      }
+      Box<Range> lastMinifiedRange = new Box<>(minifiedRange);
+      int lastMappedIndex = 0;
+      for (int i = 0; i < mappedRanges.size(); i++) {
+        MappedRange mappedRange = mappedRanges.get(i);
+        Range lastMinifiedRangeFinal = lastMinifiedRange.get();
+        if (!mappedRange.minifiedRange.equals(lastMinifiedRangeFinal)) {
+          consumer.accept(
+              ListUtils.joinNewArrayList(
+                  ListUtils.map(
+                      previouslyMapped, x -> x.partitionOnMinifiedRange(lastMinifiedRangeFinal)),
+                  mappedRanges.subList(lastMappedIndex, i)));
+          lastMinifiedRange.set(mappedRange.minifiedRange);
+          lastMappedIndex = i;
+        }
+      }
+      consumer.accept(
+          ListUtils.joinNewArrayList(
+              ListUtils.map(
+                  previouslyMapped, x -> x.partitionOnMinifiedRange(lastMinifiedRange.get())),
+              mappedRanges.subList(lastMappedIndex, mappedRanges.size())));
+    }
+
     private ComposingClassBuilder getExistingClassBuilder(MethodSignature originalSignature) {
       return originalSignature.isQualified()
           ? committedPreviousClassBuilders.get(originalSignature.toHolderFromQualified())
@@ -730,135 +794,151 @@
       if (existingRanges == null || existingRanges.isEmpty()) {
         return Collections.singletonList(newRange);
       }
-      Box<Range> originalRange = new Box<>();
-      ExistingMapping mappedRangesForPosition =
-          computeExistingMapping(
-              existingRanges, (start, end) -> originalRange.set(new Range(start, end)));
-      List<MappedRange> newComposedRanges = new ArrayList<>();
       MappedRange lastExistingRange = ListUtils.last(existingRanges);
-      if (newRange.originalRange == null && newRange.minifiedRange == null) {
+      if (newRange.originalRange == null) {
         MappedRange newComposedRange =
             new MappedRange(
-                null, lastExistingRange.signature, originalRange.get(), newRange.renamedName);
+                newRange.minifiedRange, lastExistingRange.signature, null, newRange.renamedName);
         composeMappingInformation(
             newComposedRange.getAdditionalMappingInformation(),
             lastExistingRange.getAdditionalMappingInformation(),
             info -> newComposedRange.addMappingInformation(info, ConsumerUtils.emptyConsumer()));
-        newComposedRanges.add(newComposedRange);
-      } else {
-        assert newRange.minifiedRange != null;
-        // First check if the original range matches the existing minified range.
-        List<MappedRange> existingMappedRanges =
-            mappedRangesForPosition.getMappedRangesForPosition(
-                newRange.getFirstPositionOfOriginalRange(NO_RANGE_FROM));
-        if (existingMappedRanges == null) {
-          // If we cannot lookup the original position because it has been removed we compose with
-          // the existing method signature.
-          if (newRange.originalRange != null && newRange.originalRange.isPreamble()) {
-            return Collections.singletonList(
-                new MappedRange(
-                    null, lastExistingRange.signature, originalRange.get(), newRange.renamedName));
-          } else {
-            throw new MappingComposeException(
-                "Unexpected missing original position for '" + newRange + "'.");
-          }
-        }
-        // We have found an existing range for the original position.
-        MappedRange lastExistingMappedRange = ListUtils.last(existingMappedRanges);
-        // If the existing mapped minified range is equal to the original range of the new range
-        // then we have a perfect mapping that we can translate directly.
-        if (lastExistingMappedRange.minifiedRange.equals(newRange.originalRange)) {
-          computeComposedMappedRange(
-              newComposedRanges,
-              newRange,
-              existingMappedRanges,
-              computedOutlineInformation,
-              newRange.minifiedRange.from,
-              newRange.minifiedRange.to);
+        return Collections.singletonList(newComposedRange);
+      }
+      ExistingMapping mappedRangesForPosition = computeExistingMapping(existingRanges);
+      List<MappedRange> newComposedRanges = new ArrayList<>();
+      assert newRange.minifiedRange != null;
+      // First check if the original range matches the existing minified range.
+      List<MappedRange> existingMappedRanges =
+          mappedRangesForPosition.getMappedRangesForPosition(
+              newRange.getFirstPositionOfOriginalRange(NO_RANGE_FROM));
+      MappedRange lastExistingMappedRange = ListUtils.lastOrNull(existingMappedRanges);
+      int startingPosition = newRange.minifiedRange.from;
+      if (existingMappedRanges == null) {
+        // If we cannot lookup the original position because it has been removed we compose with
+        // the existing method signature.
+        if (newRange.originalRange.isPreamble()) {
+          return Collections.singletonList(
+              new MappedRange(null, lastExistingRange.signature, null, newRange.renamedName));
+        } else if (newRange.originalRange.from == 0) {
+          // Similar to the trick below we create a synthetic range to map the preamble to.
+          Pair<Integer, MappedRange> emptyRange =
+              createEmptyRange(
+                  newRange, lastExistingRange, mappedRangesForPosition, startingPosition);
+          lastExistingMappedRange = emptyRange.getSecond();
+          existingMappedRanges = Collections.singletonList(emptyRange.getSecond());
+          startingPosition += emptyRange.getFirst() + 1;
         } else {
-          // Otherwise, we have a situation where the minified range references over multiple
-          // existing ranges. We simply chop op when the range changes on the right hand side. To
-          // ensure we do not mess up the spans from the original range, we have to check if the
-          // current starting position is inside an original range, and then chop it off.
-          // Similarly, when writing the last block, we have to cut it off to match.
-          int lastStartingMinifiedFrom = newRange.minifiedRange.from;
-          for (int position = newRange.minifiedRange.from;
-              position <= newRange.minifiedRange.to;
-              position++) {
-            List<MappedRange> existingMappedRangesForPosition =
-                mappedRangesForPosition.getMappedRangesForPosition(
-                    newRange.getOriginalLineNumber(position));
-            MappedRange lastExistingMappedRangeForPosition = null;
-            if (existingMappedRangesForPosition != null) {
-              lastExistingMappedRangeForPosition = ListUtils.last(existingMappedRangesForPosition);
-            }
-            if (lastExistingMappedRangeForPosition == null
-                || !lastExistingMappedRange.minifiedRange.equals(
-                    lastExistingMappedRangeForPosition.minifiedRange)) {
-              // We have seen an existing range we have to compute a splitting for.
-              computeComposedMappedRange(
-                  newComposedRanges,
-                  newRange,
-                  existingMappedRanges,
-                  computedOutlineInformation,
-                  lastStartingMinifiedFrom,
-                  position - 1);
-              // Advance the last starting position to this point and advance the existing mapped
-              // ranges for this position.
-              lastStartingMinifiedFrom = position;
-              if (existingMappedRangesForPosition == null) {
-                if (!options.mappingComposeOptions().allowNonExistingOriginalRanges) {
-                  throw new MappingComposeException(
-                      "Unexpected missing original position for '" + newRange + "'.");
-                }
-                // We are at the first position of a hole. If we have existing ranges:
-                // 1:1:void foo():41:41 -> a
-                // 9:9:void foo():49:49 -> a
-                // We may have a new range that is:
-                // 21:29:void foo():1:9
-                // We end up here at position 2 and we have already committed
-                // 21:21:void foo():41:41.
-                // We then introduce a "fake" normal range to simulate the result of retracing one
-                // after the other to end up with:
-                // 21:21:void foo():41:41
-                // 22:28:void foo():2:8
-                // 29:29:void foo():49:49.
-                int startOriginalPosition = newRange.getOriginalLineNumber(position);
-                Integer endOriginalPosition =
-                    mappedRangesForPosition.getCeilingForPosition(position);
-                if (endOriginalPosition == null) {
-                  endOriginalPosition = newRange.getLastPositionOfOriginalRange() + 1;
-                }
-                Range newOriginalRange = new Range(startOriginalPosition, endOriginalPosition - 1);
-                MappedRange nonExistingMappedRange =
-                    new MappedRange(
-                        newOriginalRange,
-                        lastExistingMappedRange.getOriginalSignature().asMethodSignature(),
-                        newOriginalRange,
-                        lastExistingMappedRange.renamedName);
-                nonExistingMappedRange.setResidualSignatureInternal(
-                    lastExistingRange.getResidualSignature());
-                lastExistingMappedRange = nonExistingMappedRange;
-                existingMappedRanges = Collections.singletonList(nonExistingMappedRange);
-                position += (endOriginalPosition - startOriginalPosition) - 1;
-              } else {
-                lastExistingMappedRange = lastExistingMappedRangeForPosition;
-                existingMappedRanges = existingMappedRangesForPosition;
-              }
-            }
-          }
+          throw new MappingComposeException(
+              "Unexpected missing original position for '" + newRange + "'.");
+        }
+      }
+      assert lastExistingMappedRange != null;
+      // If the existing mapped minified range is equal to the original range of the new range
+      // then we have a perfect mapping that we can translate directly.
+      if (lastExistingMappedRange.minifiedRange.equals(newRange.originalRange)) {
+        computeComposedMappedRange(
+            newComposedRanges,
+            newRange,
+            existingMappedRanges,
+            computedOutlineInformation,
+            newRange.minifiedRange.from,
+            newRange.minifiedRange.to);
+        return newComposedRanges;
+      }
+      // Otherwise, we have a situation where the minified range references over multiple
+      // existing ranges. We simply chop op when the range changes on the right hand side. To
+      // ensure we do not mess up the spans from the original range, we have to check if the
+      // current starting position is inside an original range, and then chop it off.
+      // Similarly, when writing the last block, we have to cut it off to match.
+      int lastStartingMinifiedFrom = newRange.minifiedRange.from;
+      for (int position = startingPosition; position <= newRange.minifiedRange.to; position++) {
+        List<MappedRange> existingMappedRangesForPosition =
+            mappedRangesForPosition.getMappedRangesForPosition(
+                newRange.getOriginalLineNumber(position));
+        MappedRange lastExistingMappedRangeForPosition =
+            ListUtils.lastOrNull(existingMappedRangesForPosition);
+        if (lastExistingMappedRangeForPosition == null
+            || !lastExistingMappedRange.minifiedRange.equals(
+                lastExistingMappedRangeForPosition.minifiedRange)) {
+          // We have seen an existing range we have to compute a splitting for.
           computeComposedMappedRange(
               newComposedRanges,
               newRange,
               existingMappedRanges,
               computedOutlineInformation,
               lastStartingMinifiedFrom,
-              newRange.minifiedRange.to);
+              position - 1);
+          // Advance the last starting position to this point and advance the existing mapped
+          // ranges for this position.
+          lastStartingMinifiedFrom = position;
+          if (existingMappedRangesForPosition == null) {
+            if (!options.mappingComposeOptions().allowNonExistingOriginalRanges) {
+              throw new MappingComposeException(
+                  "Unexpected missing original position for '" + newRange + "'.");
+            }
+            // We are at the first position of a hole. If we have existing ranges:
+            // 1:1:void foo():41:41 -> a
+            // 9:9:void foo():49:49 -> a
+            // We may have a new range that is:
+            // 21:29:void foo():1:9
+            // We end up here at position 2 and we have already committed
+            // 21:21:void foo():41:41.
+            // We then introduce a "fake" normal range to simulate the result of retracing one after
+            // the other to end up with:
+            // 21:21:void foo():41:41
+            // 22:28:void foo():2:8
+            // 29:29:void foo():49:49.
+            Pair<Integer, MappedRange> emptyRange =
+                createEmptyRange(
+                    newRange,
+                    lastExistingMappedRange,
+                    mappedRangesForPosition,
+                    newRange.getOriginalLineNumber(position));
+            lastExistingMappedRange = emptyRange.getSecond();
+            existingMappedRanges = Collections.singletonList(emptyRange.getSecond());
+            position += emptyRange.getFirst();
+          } else {
+            lastExistingMappedRange = lastExistingMappedRangeForPosition;
+            existingMappedRanges = existingMappedRangesForPosition;
+          }
         }
       }
+      computeComposedMappedRange(
+          newComposedRanges,
+          newRange,
+          existingMappedRanges,
+          computedOutlineInformation,
+          lastStartingMinifiedFrom,
+          newRange.minifiedRange.to);
       return newComposedRanges;
     }
 
+    private Pair<Integer, MappedRange> createEmptyRange(
+        MappedRange newRange,
+        MappedRange lastExistingMappedRange,
+        ExistingMapping mappedRangesForPosition,
+        int position) {
+      int startOriginalPosition = newRange.getOriginalLineNumber(position);
+      Integer endOriginalPosition =
+          mappedRangesForPosition.getCeilingForPosition(startOriginalPosition);
+      if (endOriginalPosition == null) {
+        endOriginalPosition = newRange.getLastPositionOfOriginalRange();
+      } else if (endOriginalPosition > startOriginalPosition) {
+        endOriginalPosition = endOriginalPosition - 1;
+      }
+      Range newOriginalRange = new Range(startOriginalPosition, endOriginalPosition);
+      MappedRange nonExistingMappedRange =
+          new MappedRange(
+              newOriginalRange,
+              lastExistingMappedRange.getOriginalSignature().asMethodSignature(),
+              newOriginalRange,
+              lastExistingMappedRange.getRenamedName());
+      nonExistingMappedRange.setResidualSignatureInternal(
+          lastExistingMappedRange.getResidualSignature());
+      return Pair.create((endOriginalPosition - startOriginalPosition), nonExistingMappedRange);
+    }
+
     public interface ExistingMapping {
 
       Integer getCeilingForPosition(int i);
@@ -870,8 +950,7 @@
      * Builds a position to mapped ranges for mappings by looking up all mapped ranges for a given
      * position.
      */
-    private ExistingMapping computeExistingMapping(
-        List<MappedRange> existingRanges, BiConsumer<Integer, Integer> positions) {
+    private ExistingMapping computeExistingMapping(List<MappedRange> existingRanges) {
       TreeMap<Integer, List<MappedRange>> mappedRangesForPosition = new TreeMap<>();
       List<MappedRange> currentRangesForPosition = new ArrayList<>();
       int startExisting = NO_RANGE_FROM;
@@ -899,9 +978,6 @@
           currentRangesForPosition = new ArrayList<>();
         }
       }
-      if (startExisting > NO_RANGE_FROM) {
-        positions.accept(startExisting, endExisting);
-      }
       boolean finalIsCatchAll = isCatchAll;
       List<MappedRange> finalCurrentRangesForPosition = currentRangesForPosition;
       return new ExistingMapping() {
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index a3cf547..aebad6d 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -12,7 +12,6 @@
 import com.android.tools.r8.Version;
 import com.android.tools.r8.references.Reference;
 import com.android.tools.r8.references.TypeReference;
-import com.android.tools.r8.retrace.RetraceCommand.Builder;
 import com.android.tools.r8.retrace.internal.ResultWithContextImpl;
 import com.android.tools.r8.retrace.internal.RetraceAbortException;
 import com.android.tools.r8.retrace.internal.StackTraceElementStringProxy;
@@ -64,9 +63,10 @@
               + "[--regex <regexp>, --verbose, --info, --quiet, --verify-mapping-file-hash]",
           "  where <proguard-map> is an r8 generated mapping file.");
 
-  private static Builder parseArguments(String[] args, DiagnosticsHandler diagnosticsHandler) {
+  private static RetraceCommand.Builder parseArguments(
+      String[] args, DiagnosticsHandler diagnosticsHandler) {
     ParseContext context = new ParseContext(args);
-    Builder builder = RetraceCommand.builder(diagnosticsHandler);
+    RetraceCommand.Builder builder = RetraceCommand.builder(diagnosticsHandler);
     boolean hasSetProguardMap = false;
     boolean hasSetStackTrace = false;
     boolean hasSetQuiet = false;
@@ -430,7 +430,7 @@
   }
 
   private static void run(String[] args, DiagnosticsHandler diagnosticsHandler) {
-    Builder builder = parseArguments(args, diagnosticsHandler);
+    RetraceCommand.Builder builder = parseArguments(args, diagnosticsHandler);
     if (builder == null) {
       // --help or --version was an argument to list
       if (Arrays.asList(args).contains("--version")) {
@@ -491,6 +491,48 @@
     }
   }
 
+  public static <T, ST extends StackTraceElementProxy<T, ST>> Builder<T, ST> builder() {
+    return new Builder<>();
+  }
+
+  @Keep
+  public static class Builder<T, ST extends StackTraceElementProxy<T, ST>> {
+
+    private StackTraceLineParser<T, ST> stackTraceLineParser;
+    private StackTraceElementProxyRetracer<T, ST> proxyRetracer;
+    private DiagnosticsHandler diagnosticsHandler;
+    protected boolean isVerbose;
+
+    public Builder<T, ST> setStackTraceLineParser(
+        StackTraceLineParser<T, ST> stackTraceLineParser) {
+      this.stackTraceLineParser = stackTraceLineParser;
+      return this;
+    }
+
+    public Builder<T, ST> setRetracer(Retracer retracer) {
+      return setProxyRetracer(StackTraceElementProxyRetracer.createDefault(retracer));
+    }
+
+    public Builder<T, ST> setProxyRetracer(StackTraceElementProxyRetracer<T, ST> proxyRetracer) {
+      this.proxyRetracer = proxyRetracer;
+      return this;
+    }
+
+    public Builder<T, ST> setDiagnosticsHandler(DiagnosticsHandler diagnosticsHandler) {
+      this.diagnosticsHandler = diagnosticsHandler;
+      return this;
+    }
+
+    public Builder<T, ST> setVerbose(boolean isVerbose) {
+      this.isVerbose = isVerbose;
+      return this;
+    }
+
+    public Retrace<T, ST> build() {
+      return new Retrace<>(stackTraceLineParser, proxyRetracer, diagnosticsHandler, isVerbose);
+    }
+  }
+
   private static class RetraceDiagnosticsHandler implements DiagnosticsHandler {
 
     private final DiagnosticsHandler diagnosticsHandler;
diff --git a/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java b/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
index ea58acd..86af9c0 100644
--- a/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
+++ b/src/main/java/com/android/tools/r8/retrace/internal/RetraceMethodResultImpl.java
@@ -17,10 +17,13 @@
 import com.android.tools.r8.retrace.RetracedSourceFile;
 import com.android.tools.r8.retrace.internal.RetraceClassResultImpl.RetraceClassElementImpl;
 import com.android.tools.r8.utils.ListUtils;
+import com.android.tools.r8.utils.OptionalBool;
 import com.android.tools.r8.utils.Pair;
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
 import java.util.OptionalInt;
+import java.util.Set;
 import java.util.function.Function;
 import java.util.stream.Stream;
 
@@ -31,6 +34,7 @@
   private final List<Pair<RetraceClassElementImpl, List<MemberNamingWithMappedRangesOfName>>>
       mappedRanges;
   private final RetracerImpl retracer;
+  private OptionalBool isAmbiguousCache = OptionalBool.UNKNOWN;
 
   RetraceMethodResultImpl(
       RetraceClassResultImpl classResult,
@@ -47,11 +51,33 @@
 
   @Override
   public boolean isAmbiguous() {
+    if (!isAmbiguousCache.isUnknown()) {
+      return isAmbiguousCache.isTrue();
+    }
     if (mappedRanges.size() > 1) {
+      isAmbiguousCache = OptionalBool.TRUE;
       return true;
     }
     List<MemberNamingWithMappedRangesOfName> mappedRangesOfNames = mappedRanges.get(0).getSecond();
-    return mappedRangesOfNames != null && mappedRangesOfNames.size() > 1;
+    if (mappedRangesOfNames == null || mappedRangesOfNames.size() < 2) {
+      isAmbiguousCache = OptionalBool.FALSE;
+      return false;
+    }
+    MethodSignature outermostSignature =
+        ListUtils.last(mappedRangesOfNames.get(0).getMappedRanges())
+            .getOriginalSignature()
+            .asMethodSignature();
+    for (int i = 1; i < mappedRangesOfNames.size(); i++) {
+      if (!outermostSignature.equals(
+          ListUtils.last(mappedRangesOfNames.get(i).getMappedRanges())
+              .getOriginalSignature()
+              .asMethodSignature())) {
+        isAmbiguousCache = OptionalBool.TRUE;
+        return true;
+      }
+    }
+    isAmbiguousCache = OptionalBool.FALSE;
+    return false;
   }
 
   @Override
@@ -181,30 +207,39 @@
                                 classElement.getRetracedClass().getClassReference())),
                         null));
               }
-              return ListUtils.map(
-                  memberNamingsWithMappedRange,
+              Set<MethodSignature> seen = new HashSet<>();
+              List<ElementImpl> newElements = new ArrayList<>(memberNamingsWithMappedRange.size());
+              memberNamingsWithMappedRange.forEach(
                   memberNamingWithMappedRangesOfName -> {
-                    MemberNaming memberNaming =
-                        memberNamingWithMappedRangesOfName.getMemberNaming();
                     MethodSignature originalSignature =
-                        memberNaming != null
-                            ? memberNaming.getOriginalSignature().asMethodSignature()
-                            : ListUtils.last(memberNamingWithMappedRangesOfName.getMappedRanges())
-                                .getOriginalSignature()
-                                .asMethodSignature();
-                    MethodReference methodReference =
-                        RetraceUtils.methodReferenceFromMethodSignature(
-                            originalSignature, classElement.getRetracedClass().getClassReference());
-                    return new ElementImpl(
-                        this,
-                        classElement,
-                        RetracedMethodReferenceImpl.create(methodReference),
-                        memberNamingWithMappedRangesOfName);
-                  })
-                  .stream();
+                        getMethodSignatureFromMapping(memberNamingWithMappedRangesOfName);
+                    if (seen.add(originalSignature)) {
+                      MethodReference methodReference =
+                          RetraceUtils.methodReferenceFromMethodSignature(
+                              originalSignature,
+                              classElement.getRetracedClass().getClassReference());
+                      newElements.add(
+                          new ElementImpl(
+                              this,
+                              classElement,
+                              RetracedMethodReferenceImpl.create(methodReference),
+                              memberNamingWithMappedRangesOfName));
+                    }
+                  });
+              return newElements.stream();
             });
   }
 
+  private MethodSignature getMethodSignatureFromMapping(
+      MemberNamingWithMappedRangesOfName memberNamingWithMappedRanges) {
+    MemberNaming memberNaming = memberNamingWithMappedRanges.getMemberNaming();
+    return (memberNaming != null && !isAmbiguous())
+        ? memberNaming.getOriginalSignature().asMethodSignature()
+        : ListUtils.last(memberNamingWithMappedRanges.getMappedRanges())
+            .getOriginalSignature()
+            .asMethodSignature();
+  }
+
   public static class ElementImpl implements RetraceMethodElement {
 
     private final RetracedMethodReferenceImpl methodReference;
@@ -228,7 +263,7 @@
       if (mapping == null) {
         return false;
       }
-      if (mapping.getMemberNaming() != null) {
+      if (mapping.getMemberNaming() != null && !retraceMethodResult.isAmbiguous()) {
         return mapping.getMemberNaming().isCompilerSynthesized();
       } else {
         List<MappedRange> mappedRanges = mapping.getMappedRanges();
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
index 9269a2a..e13dc82 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
@@ -346,7 +346,7 @@
     return result;
   }
 
-  protected StringBuilder append(StringBuilder builder, boolean includeMemberRules) {
+  protected StringBuilder append(StringBuilder builder) {
     appendAnnotations(classAnnotations, builder);
     boolean needsSpaceBeforeClassType =
         StringUtils.appendNonEmpty(builder, null, classAccessFlags, null)
@@ -366,7 +366,7 @@
       appendAnnotations(inheritanceAnnotations, builder);
       builder.append(inheritanceClassName);
     }
-    if (includeMemberRules && !memberRules.isEmpty()) {
+    if (!memberRules.isEmpty()) {
       builder.append(" {").append(System.lineSeparator());
       memberRules.forEach(memberRule -> {
         builder.append("  ");
@@ -390,15 +390,8 @@
     }
   }
 
-  /**
-   * Short String representation without member rules.
-   */
-  public String toShortString() {
-    return append(new StringBuilder(), false).toString();
-  }
-
   @Override
   public String toString() {
-    return append(new StringBuilder(), true).toString();
+    return append(new StringBuilder()).toString();
   }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index b4e83f7..d175b29 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -683,7 +683,7 @@
       builder.append('\n');
     }
     for (ProguardConfigurationRule rule : rules) {
-      rule.append(builder, true);
+      rule.append(builder);
       builder.append('\n');
     }
     return builder.toString();
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
index ea30b42..b2c90e6 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationRule.java
@@ -219,12 +219,12 @@
   }
 
   @Override
-  protected StringBuilder append(StringBuilder builder, boolean includeMemberRules) {
+  protected StringBuilder append(StringBuilder builder) {
     builder.append("-");
     builder.append(typeString());
     StringUtils.appendNonEmpty(builder, ",", modifierString(), null);
     builder.append(' ');
-    super.append(builder, includeMemberRules);
+    super.append(builder);
     return builder;
   }
 }
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
index f060d22..bd09578 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
@@ -298,4 +298,11 @@
   String typeString() {
     return "if";
   }
+
+  @Override
+  protected StringBuilder append(StringBuilder builder) {
+    super.append(builder);
+    builder.append('\n');
+    return subsequentRule.append(builder);
+  }
 }
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
index 0a8b899..63ed0ca 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevelUtils.java
@@ -94,11 +94,9 @@
       DexMethod original,
       AndroidApiLevelCompute androidApiLevelCompute,
       InternalOptions options) {
-    // If we are not using the api database and we have the platform build, then we assume we are
-    // running with boot class path as min api and all definitions are accessible at runtime.
     if (!androidApiLevelCompute.isEnabled()) {
       assert !options.apiModelingOptions().enableLibraryApiModeling;
-      return options.isAndroidPlatformBuildOrMinApiPlatform();
+      return false;
     }
     assert options.apiModelingOptions().enableLibraryApiModeling;
     ComputedApiLevel apiLevel =
@@ -117,10 +115,6 @@
   }
 
   public static boolean isApiSafeForReference(LibraryDefinition definition, AppView<?> appView) {
-    if (appView.options().isAndroidPlatformBuildOrMinApiPlatform()) {
-      assert definition != null;
-      return true;
-    }
     return isApiSafeForReference(
         definition, appView.apiLevelCompute(), appView.options(), appView.dexItemFactory());
   }
@@ -130,7 +124,7 @@
       AndroidApiLevelCompute androidApiLevelCompute,
       InternalOptions options,
       DexItemFactory factory) {
-    if (!options.apiModelingOptions().enableApiCallerIdentification) {
+    if (!options.apiModelingOptions().isApiLibraryModelingEnabled()) {
       return factory.libraryTypesAssumedToBePresent.contains(definition.getContextType());
     }
     ComputedApiLevel apiLevel =
@@ -141,7 +135,7 @@
 
   private static boolean isApiSafeForReference(
       LibraryDefinition newDefinition, LibraryDefinition oldDefinition, AppView<?> appView) {
-    assert appView.options().apiModelingOptions().enableApiCallerIdentification;
+    assert appView.options().apiModelingOptions().isApiLibraryModelingEnabled();
     assert !isApiSafeForReference(newDefinition, appView)
         : "Clients should first check if the definition is present on all apis since the min api";
     AndroidApiLevelCompute androidApiLevelCompute = appView.apiLevelCompute();
@@ -179,9 +173,9 @@
       // Program and classpath classes are not api level dependent.
       return true;
     }
-    if (!appView.options().apiModelingOptions().isApiCallerIdentificationEnabled()) {
+    if (!appView.options().apiModelingOptions().isApiLibraryModelingEnabled()) {
       // Conservatively bail out if we don't have api modeling.
-      return appView.options().isAndroidPlatformBuildOrMinApiPlatform();
+      return false;
     }
     LibraryClass newBaseLibraryClass = newBaseClass.asLibraryClass();
     if (isApiSafeForReference(newBaseLibraryClass, appView)) {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index 9ada479..c3ea9e2 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -274,7 +274,7 @@
 
   public void configureAndroidPlatformBuild(boolean isAndroidPlatformBuild) {
     assert !androidPlatformBuild;
-    if (isAndroidPlatformBuildOrMinApiPlatform()) {
+    if (isAndroidPlatformBuild || minApiLevel.isPlatform()) {
       apiModelingOptions().disableApiModeling();
     }
     if (!isAndroidPlatformBuild) {
@@ -290,10 +290,6 @@
     return androidPlatformBuild;
   }
 
-  public boolean isAndroidPlatformBuildOrMinApiPlatform() {
-    return androidPlatformBuild || minApiLevel.isPlatform();
-  }
-
   public boolean printTimes = System.getProperty("com.android.tools.r8.printtimes") != null;
   // To print memory one also have to enable printtimes.
   public boolean printMemory = System.getProperty("com.android.tools.r8.printmemory") != null;
diff --git a/src/main/java/com/android/tools/r8/utils/ListUtils.java b/src/main/java/com/android/tools/r8/utils/ListUtils.java
index 406d482..430e670 100644
--- a/src/main/java/com/android/tools/r8/utils/ListUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/ListUtils.java
@@ -4,6 +4,7 @@
 
 package com.android.tools.r8.utils;
 
+import com.android.tools.r8.naming.ClassNamingForNameMapper.MappedRange;
 import com.google.common.collect.ImmutableList;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -264,6 +265,10 @@
     }
   }
 
+  public static MappedRange lastOrNull(List<MappedRange> existingMappedRanges) {
+    return existingMappedRanges == null ? null : last(existingMappedRanges);
+  }
+
   public interface ReferenceAndIntConsumer<T> {
     void accept(T item, int index);
   }
@@ -328,4 +333,11 @@
     }
     return true;
   }
+
+  public static <T> List<T> joinNewArrayList(List<T> one, List<T> other) {
+    ArrayList<T> ts = new ArrayList<>(one.size() + other.size());
+    ts.addAll(one);
+    ts.addAll(other);
+    return ts;
+  }
 }
diff --git a/src/main/keep.txt b/src/main/keep.txt
index 689e5b5..2213ce9 100644
--- a/src/main/keep.txt
+++ b/src/main/keep.txt
@@ -49,3 +49,5 @@
 -keep class com.android.tools.r8.jetbrains.kotlin.SafePublicationLazyImpl {
   java.lang.Object getValue();
 }
+# Test in this class is using the class name to fing the original .java file.
+-keep class com.android.tools.r8.ir.desugar.varhandle.VarHandleDesugaringMethods
diff --git a/src/test/examplesJava9/varhandle/ArrayOfInt.java b/src/test/examplesJava9/varhandle/ArrayOfInt.java
index c63f79d..dd4445f 100644
--- a/src/test/examplesJava9/varhandle/ArrayOfInt.java
+++ b/src/test/examplesJava9/varhandle/ArrayOfInt.java
@@ -98,6 +98,88 @@
     }
   }
 
+  public static void testGetVolatile() {
+    System.out.println("testGetVolatile");
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(int[].class);
+    int[] array = new int[2];
+
+    arrayVarHandle.set(array, 0, 1);
+    arrayVarHandle.set(array, 1, 2);
+
+    System.out.println(arrayVarHandle.getVolatile(array, 0));
+    System.out.println(arrayVarHandle.getVolatile(array, 1));
+    System.out.println((Object) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((Object) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((int) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((int) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((long) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((long) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((float) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((float) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((double) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((double) arrayVarHandle.getVolatile(array, 1));
+    try {
+      System.out.println((boolean) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((boolean) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((byte) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((byte) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((short) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((short) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((char) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((char) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((String) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((String) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+  }
+
   public static void testSet() {
     System.out.println("testSet");
 
@@ -236,7 +318,285 @@
     }
   }
 
-  public void testCompareAndSet() {
+  public static void testSetVolatile() {
+    System.out.println("testSetVolatile");
+
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(int[].class);
+    int[] array = new int[2];
+
+    // int and Integer values.
+    arrayVarHandle.setVolatile(array, 0, 1);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, 2);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, Integer.valueOf(3));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, Integer.valueOf(4));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+
+    // int and Integer compatible values.
+    arrayVarHandle.setVolatile(array, 0, (byte) 5);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, (byte) 6);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, Byte.valueOf((byte) 7));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, Byte.valueOf((byte) 8));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, '0');
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, '1');
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, Character.valueOf('2'));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, Character.valueOf('3'));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, (short) 9);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, (short) 10);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, Short.valueOf((short) 11));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, Short.valueOf((short) 12));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+
+    // int and Integer non-compatible values.
+    try {
+      arrayVarHandle.setVolatile(array, 0, true);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, 13L);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, Long.valueOf(13L));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, 1.3f);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, Float.valueOf(1.3f));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, 1.4);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, Double.valueOf(1.4));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, new Object());
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    } catch (RuntimeException e) {
+      // The Art and desugaring throws WrongMethodTypeException.
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, "X");
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+  }
+
+  public static void testSetRelease() {
+    System.out.println("testSetRelease");
+
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(int[].class);
+    int[] array = new int[2];
+
+    // int and Integer values.
+    arrayVarHandle.setRelease(array, 0, 1);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, 2);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, Integer.valueOf(3));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, Integer.valueOf(4));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+
+    // int and Integer compatible values.
+    arrayVarHandle.setRelease(array, 0, (byte) 5);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, (byte) 6);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, Byte.valueOf((byte) 7));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, Byte.valueOf((byte) 8));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, '0');
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, '1');
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, Character.valueOf('2'));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, Character.valueOf('3'));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, (short) 9);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, (short) 10);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, Short.valueOf((short) 11));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, Short.valueOf((short) 12));
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+
+    // int and Integer non-compatible values.
+    try {
+      arrayVarHandle.setRelease(array, 0, true);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, 13L);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, Long.valueOf(13L));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, 1.3f);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, Float.valueOf(1.3f));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, 1.4);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, Double.valueOf(1.4));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, new Object());
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    } catch (RuntimeException e) {
+      // The Art and desugaring throws WrongMethodTypeException.
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, "X");
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((int) arrayVarHandle.get(array, 0));
+      System.out.println((int) arrayVarHandle.get(array, 1));
+    }
+  }
+
+  public static void testCompareAndSet() {
+    System.out.println("testCompareAndSet");
+
     VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(int[].class);
     int[] array = new int[2];
     arrayVarHandle.set(array, 0, 1);
@@ -255,6 +615,30 @@
     System.out.println((int) arrayVarHandle.get(array, 1));
   }
 
+  // This test is not testing weakCompareAndSet behaviour, but assuming it behaves like
+  // compareAndSet, that is without any spurious failures. This is the desugaring behaviour, as
+  // as there is no weakCompareAndSet primitive in sun.misc.Unsafe, only compareAndSwapXXX.
+  public static void testWeakCompareAndSet() {
+    System.out.println("testWeakCompareAndSet");
+
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(int[].class);
+    int[] array = new int[2];
+    arrayVarHandle.set(array, 0, 1);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.weakCompareAndSet(array, 1, 1, 3);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    arrayVarHandle.weakCompareAndSet(array, 1, 0, 2);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+    // TODO(b/247076137): Handle boxed.
+    // arrayVarHandle.waekCompareAndSet(array, 1, 2, box(3));
+    arrayVarHandle.weakCompareAndSet(array, 1, 2, 3);
+    System.out.println((int) arrayVarHandle.get(array, 0));
+    System.out.println((int) arrayVarHandle.get(array, 1));
+  }
+
   public static void testArrayVarHandleForNonSingleDimension() {
     System.out.println("testArrayVarHandleForNonSingleDimension");
     try {
@@ -273,7 +657,12 @@
 
   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
     testGet();
+    testGetVolatile();
     testSet();
+    testSetVolatile();
+    testSetRelease();
+    testCompareAndSet();
+    testWeakCompareAndSet();
     testArrayVarHandleForNonSingleDimension();
   }
 }
diff --git a/src/test/examplesJava9/varhandle/ArrayOfLong.java b/src/test/examplesJava9/varhandle/ArrayOfLong.java
index c909319..e66a441 100644
--- a/src/test/examplesJava9/varhandle/ArrayOfLong.java
+++ b/src/test/examplesJava9/varhandle/ArrayOfLong.java
@@ -108,6 +108,98 @@
     }
   }
 
+  public static void testGetVolatile() {
+    System.out.println("testGetVolatile");
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(long[].class);
+    long[] array = new long[2];
+
+    arrayVarHandle.set(array, 0, 1L);
+    arrayVarHandle.set(array, 1, 2L);
+
+    System.out.println(arrayVarHandle.getVolatile(array, 0));
+    System.out.println(arrayVarHandle.getVolatile(array, 1));
+    System.out.println((Object) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((Object) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((long) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((long) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((float) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((float) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((double) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((double) arrayVarHandle.getVolatile(array, 1));
+    try {
+      System.out.println((boolean) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((boolean) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((byte) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((byte) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((short) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((short) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((char) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((char) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((int) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((int) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((String) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((String) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+  }
+
   public static void testSet() {
     System.out.println("testSet");
 
@@ -242,16 +334,329 @@
     }
   }
 
+  public static void testSetVolatile() {
+    System.out.println("testSetVolatile");
+
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(long[].class);
+    long[] array = new long[2];
+
+    // long and Long values.
+    arrayVarHandle.setVolatile(array, 0, 1L);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, 2L);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, Long.valueOf(3L));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, Long.valueOf(4L));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+
+    // long and Long compatible values.
+    arrayVarHandle.setVolatile(array, 0, (byte) 5);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, (byte) 6);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, Byte.valueOf((byte) 7));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, Byte.valueOf((byte) 8));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, '0');
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, '1');
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, Character.valueOf('2'));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, Character.valueOf('3'));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, (short) 9);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, (short) 10);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, Short.valueOf((short) 11));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, Short.valueOf((short) 12));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, 13);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, 14);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 0, Integer.valueOf(15));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setVolatile(array, 1, Integer.valueOf(16));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+
+    // long and Long non-compatible values.
+    try {
+      arrayVarHandle.setVolatile(array, 0, true);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, 1.3f);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, Float.valueOf(1.3f));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, 1.4);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, Double.valueOf(1.4));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, new Object());
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    } catch (RuntimeException e) {
+      // The Art and desugaring throws WrongMethodTypeException.
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setVolatile(array, 0, "X");
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+  }
+
+  public static void testSetRelease() {
+    System.out.println("testSetRelease");
+
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(long[].class);
+    long[] array = new long[2];
+
+    // long and Long values.
+    arrayVarHandle.setRelease(array, 0, 1L);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, 2L);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, Long.valueOf(3L));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, Long.valueOf(4L));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+
+    // long and Long compatible values.
+    arrayVarHandle.setRelease(array, 0, (byte) 5);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, (byte) 6);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, Byte.valueOf((byte) 7));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, Byte.valueOf((byte) 8));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, '0');
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, '1');
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, Character.valueOf('2'));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, Character.valueOf('3'));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, (short) 9);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, (short) 10);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, Short.valueOf((short) 11));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, Short.valueOf((short) 12));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, 13);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, 14);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 0, Integer.valueOf(15));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.setRelease(array, 1, Integer.valueOf(16));
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+
+    // long and Long non-compatible values.
+    try {
+      arrayVarHandle.setRelease(array, 0, true);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, 1.3f);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, Float.valueOf(1.3f));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, 1.4);
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, Double.valueOf(1.4));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, new Object());
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    } catch (RuntimeException e) {
+      // The Art and desugaring throws WrongMethodTypeException.
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+    try {
+      arrayVarHandle.setRelease(array, 0, "X");
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println((long) arrayVarHandle.get(array, 0));
+      System.out.println((long) arrayVarHandle.get(array, 1));
+    }
+  }
+
+  public static void testCompareAndSet() {
+    System.out.println("testCompareAndSet");
+
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(long[].class);
+    long[] array = new long[2];
+    arrayVarHandle.set(array, 0, 1L);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.compareAndSet(array, 1, 1L, 3L);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.compareAndSet(array, 1, 0, 2);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    // TODO(b/247076137): Handle boxed.
+    // arrayVarHandle.compareAndSet(array, 1, 2, box(3));
+    arrayVarHandle.compareAndSet(array, 1, 2, 3);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+  }
+
+  // This test is not testing weakCompareAndSet behaviour, but assuming it behaves like
+  // compareAndSet, that is without any spurious failures. This is the desugaring behaviour, as
+  // as there is no weakCompareAndSet primitive in sun.misc.Unsafe, only compareAndSwapXXX.
+  public static void testWeakCompareAndSet() {
+    System.out.println("testWeakCompareAndSet");
+
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(long[].class);
+    long[] array = new long[2];
+    arrayVarHandle.set(array, 0, 1L);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.weakCompareAndSet(array, 1, 1L, 3L);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    arrayVarHandle.weakCompareAndSet(array, 1, 0, 2);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+    // TODO(b/247076137): Handle boxed.
+    // arrayVarHandle.weakCompareAndSet(array, 1, 2, box(3));
+    arrayVarHandle.weakCompareAndSet(array, 1, 2, 3);
+    System.out.println((long) arrayVarHandle.get(array, 0));
+    System.out.println((long) arrayVarHandle.get(array, 1));
+  }
+
   public static void testArrayVarHandleForNonSingleDimension() {
     System.out.println("testArrayVarHandleForNonSingleDimension");
     try {
-      MethodHandles.arrayElementVarHandle(int.class);
+      MethodHandles.arrayElementVarHandle(long.class);
       System.out.println("Unexpected success");
     } catch (IllegalArgumentException e) {
       System.out.println("IllegalArgumentException");
     }
     try {
-      MethodHandles.arrayElementVarHandle(int[][].class);
+      MethodHandles.arrayElementVarHandle(long[][].class);
       System.out.println("Got array element VarHandle");
     } catch (UnsupportedOperationException e) {
       System.out.println("UnsupportedOperationException");
@@ -260,7 +665,12 @@
 
   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
     testGet();
+    testGetVolatile();
     testSet();
+    testSetVolatile();
+    testSetRelease();
+    testCompareAndSet();
+    testWeakCompareAndSet();
     testArrayVarHandleForNonSingleDimension();
   }
 }
diff --git a/src/test/examplesJava9/varhandle/ArrayOfObject.java b/src/test/examplesJava9/varhandle/ArrayOfObject.java
index ab9a6bd..f7189d8 100644
--- a/src/test/examplesJava9/varhandle/ArrayOfObject.java
+++ b/src/test/examplesJava9/varhandle/ArrayOfObject.java
@@ -166,6 +166,143 @@
     }
   }
 
+  public static void unsupportedGetVolatileConversion(VarHandle arrayVarHandle, Object[] array) {
+    try {
+      System.out.println((boolean) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((boolean) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((byte) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((byte) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((short) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((short) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((char) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((char) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((String) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((String) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+  }
+
+  public static void testGetVolatile() {
+    System.out.println("testGetVolatile");
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(Object[].class);
+    Object[] array = new Object[2];
+
+    arrayVarHandle.set(array, 0, 1);
+    arrayVarHandle.set(array, 1, 2);
+
+    System.out.println(arrayVarHandle.getVolatile(array, 0));
+    System.out.println(arrayVarHandle.getVolatile(array, 1));
+    System.out.println((Object) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((Object) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((int) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((int) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((long) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((long) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((float) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((float) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((double) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((double) arrayVarHandle.getVolatile(array, 1));
+    unsupportedGetVolatileConversion(arrayVarHandle, array);
+
+    arrayVarHandle.set(array, 0, 3L);
+    arrayVarHandle.set(array, 1, 4L);
+
+    System.out.println(arrayVarHandle.getVolatile(array, 0));
+    System.out.println(arrayVarHandle.getVolatile(array, 1));
+    System.out.println((Object) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((Object) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((long) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((long) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((float) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((float) arrayVarHandle.getVolatile(array, 1));
+    System.out.println((double) arrayVarHandle.getVolatile(array, 0));
+    System.out.println((double) arrayVarHandle.getVolatile(array, 1));
+    unsupportedGetVolatileConversion(arrayVarHandle, array);
+    try {
+      System.out.println((int) arrayVarHandle.getVolatile(array, 0));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((int) arrayVarHandle.getVolatile(array, 1));
+      System.out.println("Unexpected success");
+    } catch (ClassCastException e) {
+      // The reference implementation throws ClassCastException.
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+  }
+
   public static void testSet() {
     System.out.println("testSet");
 
@@ -265,6 +402,204 @@
     }
   }
 
+  public static void testSetVolatile() {
+    System.out.println("testSetVolatile");
+
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(Object[].class);
+    Object[] array = new Object[2];
+
+    Object o;
+    {
+      int index = 0;
+      byte b;
+      arrayVarHandle.setVolatile(array, index, (byte) 5);
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((byte) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Byte);
+      b = (byte) arrayVarHandle.get(array, index);
+      System.out.println(b == (byte) 5);
+      arrayVarHandle.setVolatile(array, index, Byte.valueOf((byte) 6));
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((byte) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Byte);
+      b = (byte) arrayVarHandle.get(array, index);
+      System.out.println(b == 6);
+    }
+    {
+      int index = 0;
+      short s;
+      arrayVarHandle.setVolatile(array, index, (short) 7);
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((short) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Short);
+      s = (short) arrayVarHandle.get(array, index);
+      System.out.println(s == (short) 7);
+      arrayVarHandle.setVolatile(array, index, Short.valueOf((short) 8));
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((short) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Short);
+      s = (short) arrayVarHandle.get(array, index);
+      System.out.println(s == 8);
+    }
+    {
+      int index = 0;
+      float f;
+      arrayVarHandle.setVolatile(array, index, (float) 9.0f);
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((float) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Float);
+      f = (float) arrayVarHandle.get(array, index);
+      System.out.println(f == (float) 9.0f);
+      arrayVarHandle.setVolatile(array, index, Float.valueOf(10.0f));
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((float) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Float);
+      f = (float) arrayVarHandle.get(array, index);
+      System.out.println(f == 10.0f);
+    }
+    {
+      int index = 0;
+      double d;
+      arrayVarHandle.setVolatile(array, index, (double) 11.0);
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((double) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Double);
+      d = (double) arrayVarHandle.get(array, index);
+      System.out.println(d == (double) 11.0);
+      arrayVarHandle.setVolatile(array, index, Double.valueOf(12.0));
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((double) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Double);
+      d = (double) arrayVarHandle.get(array, index);
+      System.out.println(d == 12.0);
+    }
+    {
+      int index = 0;
+      char c;
+      arrayVarHandle.setVolatile(array, index, 'A');
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((char) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Character);
+      c = (char) arrayVarHandle.get(array, index);
+      System.out.println(c == 'A');
+      arrayVarHandle.setVolatile(array, index, Character.valueOf('B'));
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((char) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Character);
+      c = (char) arrayVarHandle.get(array, index);
+      System.out.println(c == 'B');
+    }
+  }
+
+  public static void testSetRelease() {
+    System.out.println("testSetRelease");
+
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(Object[].class);
+    Object[] array = new Object[2];
+
+    Object o;
+    {
+      int index = 0;
+      byte b;
+      arrayVarHandle.setRelease(array, index, (byte) 5);
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((byte) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Byte);
+      b = (byte) arrayVarHandle.get(array, index);
+      System.out.println(b == (byte) 5);
+      arrayVarHandle.setRelease(array, index, Byte.valueOf((byte) 6));
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((byte) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Byte);
+      b = (byte) arrayVarHandle.get(array, index);
+      System.out.println(b == 6);
+    }
+    {
+      int index = 0;
+      short s;
+      arrayVarHandle.setRelease(array, index, (short) 7);
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((short) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Short);
+      s = (short) arrayVarHandle.get(array, index);
+      System.out.println(s == (short) 7);
+      arrayVarHandle.setRelease(array, index, Short.valueOf((short) 8));
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((short) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Short);
+      s = (short) arrayVarHandle.get(array, index);
+      System.out.println(s == 8);
+    }
+    {
+      int index = 0;
+      float f;
+      arrayVarHandle.setRelease(array, index, (float) 9.0f);
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((float) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Float);
+      f = (float) arrayVarHandle.get(array, index);
+      System.out.println(f == (float) 9.0f);
+      arrayVarHandle.setRelease(array, index, Float.valueOf(10.0f));
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((float) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Float);
+      f = (float) arrayVarHandle.get(array, index);
+      System.out.println(f == 10.0f);
+    }
+    {
+      int index = 0;
+      double d;
+      arrayVarHandle.setRelease(array, index, (double) 11.0);
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((double) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Double);
+      d = (double) arrayVarHandle.get(array, index);
+      System.out.println(d == (double) 11.0);
+      arrayVarHandle.setRelease(array, index, Double.valueOf(12.0));
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((double) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Double);
+      d = (double) arrayVarHandle.get(array, index);
+      System.out.println(d == 12.0);
+    }
+    {
+      int index = 0;
+      char c;
+      arrayVarHandle.setRelease(array, index, 'A');
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((char) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Character);
+      c = (char) arrayVarHandle.get(array, index);
+      System.out.println(c == 'A');
+      arrayVarHandle.setRelease(array, index, Character.valueOf('B'));
+      System.out.println(arrayVarHandle.get(array, index));
+      System.out.println((char) arrayVarHandle.get(array, index));
+      o = arrayVarHandle.get(array, index);
+      System.out.println(o instanceof Character);
+      c = (char) arrayVarHandle.get(array, index);
+      System.out.println(c == 'B');
+    }
+  }
+
   public static void testCompareAndSet() {
     System.out.println("testCompareAndSet");
 
@@ -348,6 +683,92 @@
     System.out.println(arrayVarHandle.get(array, index));
   }
 
+  // This test is not testing weakCompareAndSet behaviour, but assuming it behaves like
+  // compareAndSet, that is without any spurious failures. This is the desugaring behaviour, as
+  // as there is no weakCompareAndSet primitive in sun.misc.Unsafe, only compareAndSwapXXX.
+  public static void testWeakCompareAndSet() {
+    System.out.println("testWeakCompareAndSet");
+
+    VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(Object[].class);
+    Object[] array = new Object[2];
+
+    int index = 0;
+    A a1 = new A(1);
+    arrayVarHandle.weakCompareAndSet(array, index, 0, a1);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, null, a1);
+    System.out.println(arrayVarHandle.get(array, index));
+    System.out.println(arrayVarHandle.get(array, index) == a1);
+    A a2 = new A(2);
+    arrayVarHandle.weakCompareAndSet(array, index, a1, a2);
+    System.out.println(arrayVarHandle.get(array, index));
+    System.out.println(arrayVarHandle.get(array, index) == a2);
+
+    arrayVarHandle.weakCompareAndSet(array, index, a2, 1);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, Integer.valueOf(1), 2);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, Integer.valueOf(2), Integer.valueOf(3));
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, Integer.valueOf(3), 4);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, 4L, 5);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, (byte) 4, 5);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, (short) 4, 5);
+    System.out.println(arrayVarHandle.get(array, index));
+
+    arrayVarHandle.weakCompareAndSet(array, index, 4, 5L);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, Long.valueOf(5), 6L);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, Long.valueOf(6), Long.valueOf(7));
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, Long.valueOf(7), 8L);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, 8, 9L);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, (byte) 8, 9);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, (short) 8, 9);
+    System.out.println(arrayVarHandle.get(array, index));
+    System.out.println(arrayVarHandle.get(array, index) == a1);
+    arrayVarHandle.weakCompareAndSet(array, index, a1, a2);
+    System.out.println(arrayVarHandle.get(array, index));
+    System.out.println(arrayVarHandle.get(array, index) == a2);
+
+    arrayVarHandle.weakCompareAndSet(array, index, a2, 1);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, Integer.valueOf(1), 2);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, Integer.valueOf(2), Integer.valueOf(3));
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, Integer.valueOf(3), 4);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, 4L, 5);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, (byte) 4, 5);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, (short) 4, 5);
+    System.out.println(arrayVarHandle.get(array, index));
+
+    arrayVarHandle.weakCompareAndSet(array, index, 4, 5L);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, Long.valueOf(5), 6L);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, Long.valueOf(6), Long.valueOf(7));
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, Long.valueOf(7), 8L);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, 8, 9L);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, (byte) 8, 9);
+    System.out.println(arrayVarHandle.get(array, index));
+    arrayVarHandle.weakCompareAndSet(array, index, (short) 8, 9);
+    System.out.println(arrayVarHandle.get(array, index));
+  }
+
   public static void testArrayVarHandleForNonSingleDimension() {
     System.out.println("testArrayVarHandleForNonSingleDimension");
     try {
@@ -366,8 +787,12 @@
 
   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
     testGet();
+    testGetVolatile();
     testSet();
+    testSetVolatile();
+    testSetRelease();
     testCompareAndSet();
+    testWeakCompareAndSet();
     testArrayVarHandleForNonSingleDimension();
   }
 }
diff --git a/src/test/examplesJava9/varhandle/InstanceIntField.java b/src/test/examplesJava9/varhandle/InstanceIntField.java
index aeadbcc..6970f2e 100644
--- a/src/test/examplesJava9/varhandle/InstanceIntField.java
+++ b/src/test/examplesJava9/varhandle/InstanceIntField.java
@@ -62,6 +62,50 @@
     }
   }
 
+  public static void testGetVolatile(VarHandle varHandle) {
+    System.out.println("testGetVolatile");
+
+    InstanceIntField instance = new InstanceIntField();
+    varHandle.set(instance, 1);
+
+    System.out.println(varHandle.getVolatile(instance));
+    System.out.println((Object) varHandle.getVolatile(instance));
+    System.out.println((int) varHandle.getVolatile(instance));
+    System.out.println((long) varHandle.getVolatile(instance));
+    System.out.println((float) varHandle.getVolatile(instance));
+    System.out.println((double) varHandle.getVolatile(instance));
+    try {
+      System.out.println((boolean) varHandle.getVolatile(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((byte) varHandle.getVolatile(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((short) varHandle.getVolatile(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((char) varHandle.getVolatile(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((String) varHandle.getVolatile(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+  }
+
   public static void testSet(VarHandle varHandle) {
     System.out.println("testSet");
 
@@ -127,6 +171,136 @@
     }
   }
 
+  public static void testSetVolatile(VarHandle varHandle) {
+    System.out.println("testSetVolatile");
+
+    InstanceIntField instance = new InstanceIntField();
+    System.out.println((int) varHandle.get(instance));
+
+    // int and Integer values.
+    varHandle.setVolatile(instance, (int) 1);
+    System.out.println((int) varHandle.get(instance));
+    varHandle.setVolatile(instance, Integer.valueOf(2));
+    System.out.println(varHandle.get(instance));
+
+    // int and Integer compatible values.
+    varHandle.setVolatile(instance, (byte) 3);
+    System.out.println((int) varHandle.get(instance));
+    varHandle.setVolatile(instance, Byte.valueOf((byte) 4));
+    System.out.println((int) varHandle.get(instance));
+    varHandle.setVolatile(instance, '0');
+    System.out.println((int) varHandle.get(instance));
+    varHandle.setVolatile(instance, Character.valueOf('1'));
+    System.out.println((int) varHandle.get(instance));
+    varHandle.setVolatile(instance, (short) 5);
+    System.out.println((int) varHandle.get(instance));
+    varHandle.setVolatile(instance, Short.valueOf((short) 6));
+    System.out.println((int) varHandle.get(instance));
+
+    // int and Integer non-compatible values.
+    try {
+      varHandle.setVolatile(instance, true);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setVolatile(instance, 3L);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setVolatile(instance, Long.valueOf(3));
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setVolatile(instance, "3");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setVolatile(instance, 3.0f);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setVolatile(instance, 3.0);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+  }
+
+  public static void testSetRelease(VarHandle varHandle) {
+    System.out.println("testSetRelease");
+
+    InstanceIntField instance = new InstanceIntField();
+    System.out.println((int) varHandle.get(instance));
+
+    // int and Integer values.
+    varHandle.setRelease(instance, (int) 1);
+    System.out.println((int) varHandle.get(instance));
+    varHandle.setRelease(instance, Integer.valueOf(2));
+    System.out.println(varHandle.get(instance));
+
+    // int and Integer compatible values.
+    varHandle.setRelease(instance, (byte) 3);
+    System.out.println((int) varHandle.get(instance));
+    varHandle.setRelease(instance, Byte.valueOf((byte) 4));
+    System.out.println((int) varHandle.get(instance));
+    varHandle.setRelease(instance, '0');
+    System.out.println((int) varHandle.get(instance));
+    varHandle.setRelease(instance, Character.valueOf('1'));
+    System.out.println((int) varHandle.get(instance));
+    varHandle.setRelease(instance, (short) 5);
+    System.out.println((int) varHandle.get(instance));
+    varHandle.setRelease(instance, Short.valueOf((short) 6));
+    System.out.println((int) varHandle.get(instance));
+
+    // int and Integer non-compatible values.
+    try {
+      varHandle.setRelease(instance, true);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setRelease(instance, 3L);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setRelease(instance, Long.valueOf(3));
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setRelease(instance, "3");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setRelease(instance, 3.0f);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setRelease(instance, 3.0);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+  }
+
   public static void testCompareAndSet(VarHandle varHandle) {
     System.out.println("testCompareAndSet");
 
@@ -258,11 +432,149 @@
     }
   }
 
+  // This test is not testing weakCompareAndSet behaviour, but assuming it behaves like
+  // compareAndSet, that is without any spurious failures. This is the desugaring behaviour, as
+  // as there is no weakCompareAndSet primitive in sun.misc.Unsafe, only compareAndSwapXXX.
+  public static void testWeakCompareAndSet(VarHandle varHandle) {
+    System.out.println("testWeakCompareAndSet");
+
+    InstanceIntField instance = new InstanceIntField();
+
+    // int and Integer values.
+    varHandle.weakCompareAndSet(instance, 1, 2);
+    System.out.println((int) varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, 0, 1);
+    System.out.println((int) varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, Integer.valueOf(1), 2);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, 2, Integer.valueOf(3));
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, Integer.valueOf(3), Integer.valueOf(4));
+    System.out.println(varHandle.get(instance));
+
+    // int and Integer compatible values.
+    varHandle.weakCompareAndSet(instance, (byte) 4, 5);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, 5, (byte) 6);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, (byte) 6, (byte) 7);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, Byte.valueOf((byte) 7), (byte) 8);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, (byte) 8, Byte.valueOf((byte) 9));
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, Byte.valueOf((byte) 9), Byte.valueOf((byte) 10));
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, 10, '0');
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, '0', 49);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, '1', '2');
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, (byte) 50, '3');
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, '3', (byte) 52);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, '4', '5');
+    System.out.println(varHandle.get(instance));
+
+    // int and Integer non-compatible values.
+    try {
+      varHandle.weakCompareAndSet(instance, 6L, 7L);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6L, 7);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6, Long.valueOf(7));
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, Long.valueOf(6), 7);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, Long.valueOf(6), Long.valueOf(7));
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6, 7.0f);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6.0f, 7);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6.0f, 7.0f);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6, 7.0);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6.0, 7);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6.0, 7.0);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+
+    try {
+      varHandle.weakCompareAndSet(instance, 6, "7");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, "6", 7);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, "6", "7");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+  }
+
   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
     VarHandle varHandle =
         MethodHandles.lookup().findVarHandle(InstanceIntField.class, "field", int.class);
     testGet(varHandle);
+    testGetVolatile(varHandle);
     testSet(varHandle);
+    testSetVolatile(varHandle);
+    testSetRelease(varHandle);
     testCompareAndSet(varHandle);
+    testWeakCompareAndSet(varHandle);
   }
 }
diff --git a/src/test/examplesJava9/varhandle/InstanceLongField.java b/src/test/examplesJava9/varhandle/InstanceLongField.java
index b23e692..7ecc8a7 100644
--- a/src/test/examplesJava9/varhandle/InstanceLongField.java
+++ b/src/test/examplesJava9/varhandle/InstanceLongField.java
@@ -67,6 +67,55 @@
     }
   }
 
+  public static void testGetVolatile(VarHandle varHandle) {
+    System.out.println("testGetVolatile");
+
+    InstanceLongField instance = new InstanceLongField();
+    varHandle.set(instance, 1);
+
+    System.out.println(varHandle.getVolatile(instance));
+    System.out.println((Object) varHandle.getVolatile(instance));
+    System.out.println((long) varHandle.getVolatile(instance));
+    System.out.println((float) varHandle.getVolatile(instance));
+    System.out.println((double) varHandle.getVolatile(instance));
+    try {
+      System.out.println((boolean) varHandle.getVolatile(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((byte) varHandle.getVolatile(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((short) varHandle.getVolatile(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((char) varHandle.getVolatile(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((int) varHandle.getVolatile(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+    try {
+      System.out.println((String) varHandle.getVolatile(instance));
+      System.out.println("Unexpected success");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+    }
+  }
+
   public static void testSet(VarHandle varHandle) {
     System.out.println("testSet");
 
@@ -124,6 +173,120 @@
     }
   }
 
+  public static void testSetVolatile(VarHandle varHandle) {
+    System.out.println("testSetVolatile");
+
+    InstanceLongField instance = new InstanceLongField();
+    System.out.println((long) varHandle.get(instance));
+
+    // Long value.
+    varHandle.setVolatile(instance, (long) 1);
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setVolatile(instance, Long.valueOf(2));
+    System.out.println(varHandle.get(instance));
+
+    // Long compatible values.
+    varHandle.setVolatile(instance, (byte) 3);
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setVolatile(instance, Byte.valueOf((byte) 4));
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setVolatile(instance, '0');
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setVolatile(instance, Character.valueOf('1'));
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setVolatile(instance, (short) 5);
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setVolatile(instance, Short.valueOf((short) 6));
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setVolatile(instance, (int) 7);
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setVolatile(instance, Integer.valueOf(8));
+    System.out.println((long) varHandle.get(instance));
+
+    // Long non-compatible values.
+    try {
+      varHandle.setVolatile(instance, true);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setVolatile(instance, "3");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setVolatile(instance, 3.0f);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setVolatile(instance, 3.0);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+  }
+
+  public static void testSetRelease(VarHandle varHandle) {
+    System.out.println("testSetRelease");
+
+    InstanceLongField instance = new InstanceLongField();
+    System.out.println((long) varHandle.get(instance));
+
+    // Long value.
+    varHandle.setRelease(instance, (long) 1);
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setRelease(instance, Long.valueOf(2));
+    System.out.println(varHandle.get(instance));
+
+    // Long compatible values.
+    varHandle.setRelease(instance, (byte) 3);
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setRelease(instance, Byte.valueOf((byte) 4));
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setRelease(instance, '0');
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setRelease(instance, Character.valueOf('1'));
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setRelease(instance, (short) 5);
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setRelease(instance, Short.valueOf((short) 6));
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setRelease(instance, (int) 7);
+    System.out.println((long) varHandle.get(instance));
+    varHandle.setRelease(instance, Integer.valueOf(8));
+    System.out.println((long) varHandle.get(instance));
+
+    // Long non-compatible values.
+    try {
+      varHandle.setRelease(instance, true);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setRelease(instance, "3");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setRelease(instance, 3.0f);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.setRelease(instance, 3.0);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+  }
+
   public static void testCompareAndSet(VarHandle varHandle) {
     System.out.println("testCompareAndSet");
 
@@ -233,11 +396,127 @@
     }
   }
 
+  // This test is not testing weakCompareAndSet behaviour, but assuming it behaves like
+  // compareAndSet, that is without any spurious failures. This is the desugaring behaviour, as
+  // as there is no weakCompareAndSet primitive in sun.misc.Unsafe, only compareAndSwapXXX.
+  public static void testWeakCompareAndSet(VarHandle varHandle) {
+    System.out.println("testWeakCompareAndSet");
+
+    InstanceLongField instance = new InstanceLongField();
+
+    // Long value.
+    varHandle.weakCompareAndSet(instance, 1L, 2L);
+    System.out.println((long) varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, 0L, 1L);
+    System.out.println((long) varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, Long.valueOf(1), 2);
+    System.out.println((long) varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, 2, Long.valueOf(3));
+    System.out.println((long) varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, Long.valueOf(3), Long.valueOf(4));
+    System.out.println((long) varHandle.get(instance));
+
+    // Long compatible values.
+    varHandle.weakCompareAndSet(instance, (byte) 4, 5);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, 5, (byte) 6);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, (byte) 6, (byte) 7);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, Byte.valueOf((byte) 7), (byte) 8);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, (byte) 8, Byte.valueOf((byte) 9));
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, Byte.valueOf((byte) 9), Byte.valueOf((byte) 10));
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, 10, '0');
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, '0', 49);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, '1', '2');
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, (byte) 50, '3');
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, '3', (byte) 52);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, '4', '5');
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, '5', (int) 11);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, (int) 11, (int) 12);
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, (int) 12, Integer.valueOf(13));
+    System.out.println(varHandle.get(instance));
+    varHandle.weakCompareAndSet(instance, Integer.valueOf(13), Integer.valueOf(14));
+    System.out.println(varHandle.get(instance));
+
+    // Long non-compatible values.
+    try {
+      varHandle.weakCompareAndSet(instance, 6, 7.0f);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6.0f, 7);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6.0f, 7.0f);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6, 7.0);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6.0, 7);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, 6.0, 7.0);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+
+    try {
+      varHandle.weakCompareAndSet(instance, 6, "7");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, "6", 7);
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+    try {
+      varHandle.weakCompareAndSet(instance, "6", "7");
+    } catch (RuntimeException e) {
+      checkJavaLangInvokeWrongMethodTypeException(e);
+      System.out.println(varHandle.get(instance));
+    }
+  }
+
   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
     VarHandle varHandle =
         MethodHandles.lookup().findVarHandle(InstanceLongField.class, "field", long.class);
     testGet(varHandle);
+    testGetVolatile(varHandle);
     testSet(varHandle);
+    testSetVolatile(varHandle);
+    testSetRelease(varHandle);
     testCompareAndSet(varHandle);
+    testWeakCompareAndSet(varHandle);
   }
 }
diff --git a/src/test/examplesJava9/varhandle/InstanceObjectField.java b/src/test/examplesJava9/varhandle/InstanceObjectField.java
index c951ed8..0b19a76 100644
--- a/src/test/examplesJava9/varhandle/InstanceObjectField.java
+++ b/src/test/examplesJava9/varhandle/InstanceObjectField.java
@@ -24,8 +24,8 @@
     }
   }
 
-  public static void testSet(VarHandle varHandle) {
-    System.out.println("testSet");
+  public static void testSetGet(VarHandle varHandle) {
+    System.out.println("testSetGet");
 
     InstanceObjectField instance = new InstanceObjectField();
 
@@ -161,6 +161,280 @@
     }
   }
 
+  public static void testSetVolatileGetVolatile(VarHandle varHandle) {
+    System.out.println("testSetVolatileGetVolatile");
+
+    InstanceObjectField instance = new InstanceObjectField();
+
+    System.out.println(varHandle.getVolatile(instance));
+    A a1 = new A(1);
+    varHandle.setVolatile(instance, a1);
+    System.out.println(varHandle.getVolatile(instance));
+    System.out.println(varHandle.getVolatile(instance) == a1);
+    A a2 = new A(2);
+    varHandle.setVolatile(instance, a2);
+    System.out.println(varHandle.getVolatile(instance));
+    System.out.println(varHandle.getVolatile(instance) == a2);
+
+    Object o;
+    {
+      int i;
+      varHandle.setVolatile(instance, 1);
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((int) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Integer);
+      i = (int) varHandle.getVolatile(instance);
+      System.out.println(i == 1);
+      varHandle.setVolatile(instance, Integer.valueOf(2));
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((int) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Integer);
+      i = (int) varHandle.getVolatile(instance);
+      System.out.println(i == 2);
+    }
+    {
+      long l;
+      varHandle.setVolatile(instance, 3L);
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((long) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Long);
+      l = (long) varHandle.getVolatile(instance);
+      System.out.println(l == 3L);
+      varHandle.setVolatile(instance, Long.valueOf(4L));
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((long) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Long);
+      l = (long) varHandle.getVolatile(instance);
+      System.out.println(l == 4L);
+    }
+    {
+      byte b;
+      varHandle.setVolatile(instance, (byte) 5);
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((byte) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Byte);
+      b = (byte) varHandle.getVolatile(instance);
+      System.out.println(b == (byte) 5);
+      varHandle.setVolatile(instance, Byte.valueOf((byte) 6));
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((byte) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Byte);
+      b = (byte) varHandle.getVolatile(instance);
+      System.out.println(b == 6);
+    }
+    {
+      short s;
+      varHandle.setVolatile(instance, (short) 7);
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((short) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Short);
+      s = (short) varHandle.getVolatile(instance);
+      System.out.println(s == (short) 7);
+      varHandle.setVolatile(instance, Short.valueOf((short) 8));
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((short) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Short);
+      s = (short) varHandle.getVolatile(instance);
+      System.out.println(s == 8);
+    }
+    {
+      float f;
+      varHandle.setVolatile(instance, (float) 9.0f);
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((float) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Float);
+      f = (float) varHandle.getVolatile(instance);
+      System.out.println(f == (float) 9.0f);
+      varHandle.setVolatile(instance, Float.valueOf(10.0f));
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((float) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Float);
+      f = (float) varHandle.getVolatile(instance);
+      System.out.println(f == 10.0f);
+    }
+    {
+      double d;
+      varHandle.setVolatile(instance, (double) 11.0);
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((double) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Double);
+      d = (double) varHandle.getVolatile(instance);
+      System.out.println(d == (double) 11.0);
+      varHandle.setVolatile(instance, Double.valueOf(12.0));
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((double) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Double);
+      d = (double) varHandle.getVolatile(instance);
+      System.out.println(d == 12.0);
+    }
+    {
+      char c;
+      varHandle.setVolatile(instance, 'A');
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((char) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Character);
+      c = (char) varHandle.getVolatile(instance);
+      System.out.println(c == 'A');
+      varHandle.setVolatile(instance, Character.valueOf('B'));
+      System.out.println(varHandle.getVolatile(instance));
+      System.out.println((char) varHandle.getVolatile(instance));
+      o = varHandle.getVolatile(instance);
+      System.out.println(o instanceof Character);
+      c = (char) varHandle.getVolatile(instance);
+      System.out.println(c == 'B');
+    }
+  }
+
+  public static void testSetReleaseGet(VarHandle varHandle) {
+    System.out.println("testSetReleaseGet");
+
+    InstanceObjectField instance = new InstanceObjectField();
+
+    System.out.println(varHandle.get(instance));
+    A a1 = new A(1);
+    varHandle.setRelease(instance, a1);
+    System.out.println(varHandle.get(instance));
+    System.out.println(varHandle.get(instance) == a1);
+    A a2 = new A(2);
+    varHandle.setRelease(instance, a2);
+    System.out.println(varHandle.get(instance));
+    System.out.println(varHandle.get(instance) == a2);
+
+    Object o;
+    {
+      int i;
+      varHandle.setRelease(instance, 1);
+      System.out.println(varHandle.get(instance));
+      System.out.println((int) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Integer);
+      i = (int) varHandle.get(instance);
+      System.out.println(i == 1);
+      varHandle.setRelease(instance, Integer.valueOf(2));
+      System.out.println(varHandle.get(instance));
+      System.out.println((int) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Integer);
+      i = (int) varHandle.get(instance);
+      System.out.println(i == 2);
+    }
+    {
+      long l;
+      varHandle.setRelease(instance, 3L);
+      System.out.println(varHandle.get(instance));
+      System.out.println((long) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Long);
+      l = (long) varHandle.get(instance);
+      System.out.println(l == 3L);
+      varHandle.setRelease(instance, Long.valueOf(4L));
+      System.out.println(varHandle.get(instance));
+      System.out.println((long) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Long);
+      l = (long) varHandle.get(instance);
+      System.out.println(l == 4L);
+    }
+    {
+      byte b;
+      varHandle.setRelease(instance, (byte) 5);
+      System.out.println(varHandle.get(instance));
+      System.out.println((byte) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Byte);
+      b = (byte) varHandle.get(instance);
+      System.out.println(b == (byte) 5);
+      varHandle.setRelease(instance, Byte.valueOf((byte) 6));
+      System.out.println(varHandle.get(instance));
+      System.out.println((byte) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Byte);
+      b = (byte) varHandle.get(instance);
+      System.out.println(b == 6);
+    }
+    {
+      short s;
+      varHandle.setRelease(instance, (short) 7);
+      System.out.println(varHandle.get(instance));
+      System.out.println((short) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Short);
+      s = (short) varHandle.get(instance);
+      System.out.println(s == (short) 7);
+      varHandle.setRelease(instance, Short.valueOf((short) 8));
+      System.out.println(varHandle.get(instance));
+      System.out.println((short) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Short);
+      s = (short) varHandle.get(instance);
+      System.out.println(s == 8);
+    }
+    {
+      float f;
+      varHandle.setRelease(instance, (float) 9.0f);
+      System.out.println(varHandle.get(instance));
+      System.out.println((float) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Float);
+      f = (float) varHandle.get(instance);
+      System.out.println(f == (float) 9.0f);
+      varHandle.setRelease(instance, Float.valueOf(10.0f));
+      System.out.println(varHandle.get(instance));
+      System.out.println((float) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Float);
+      f = (float) varHandle.get(instance);
+      System.out.println(f == 10.0f);
+    }
+    {
+      double d;
+      varHandle.setRelease(instance, (double) 11.0);
+      System.out.println(varHandle.get(instance));
+      System.out.println((double) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Double);
+      d = (double) varHandle.get(instance);
+      System.out.println(d == (double) 11.0);
+      varHandle.setRelease(instance, Double.valueOf(12.0));
+      System.out.println(varHandle.get(instance));
+      System.out.println((double) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Double);
+      d = (double) varHandle.get(instance);
+      System.out.println(d == 12.0);
+    }
+    {
+      char c;
+      varHandle.setRelease(instance, 'A');
+      System.out.println(varHandle.get(instance));
+      System.out.println((char) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Character);
+      c = (char) varHandle.get(instance);
+      System.out.println(c == 'A');
+      varHandle.setRelease(instance, Character.valueOf('B'));
+      System.out.println(varHandle.get(instance));
+      System.out.println((char) varHandle.get(instance));
+      o = varHandle.get(instance);
+      System.out.println(o instanceof Character);
+      c = (char) varHandle.get(instance);
+      System.out.println(c == 'B');
+    }
+  }
+
   public static void testCompareAndSet(VarHandle varHandle) {
     System.out.println("testCompareAndSet");
 
@@ -242,6 +516,90 @@
     System.out.println(varHandle.get(instance));
   }
 
+  // This test is not testing weakCompareAndSet behaviour, but assuming it behaves like
+  // compareAndSet, that is without any spurious failures. This is the desugaring behaviour, as
+  // as there is no weakCompareAndSet primitive in sun.misc.Unsafe, only compareAndSwapXXX.
+  public static void testWeakCompareAndSet(VarHandle varHandle) {
+    System.out.println("testWeakCompareAndSet");
+
+    InstanceObjectField instance = new InstanceObjectField();
+
+    A a1 = new A(1);
+    varHandle.compareAndSet(instance, 0, a1);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, null, a1);
+    System.out.println(varHandle.get(instance));
+    System.out.println(varHandle.get(instance) == a1);
+    A a2 = new A(2);
+    varHandle.compareAndSet(instance, a1, a2);
+    System.out.println(varHandle.get(instance));
+    System.out.println(varHandle.get(instance) == a2);
+
+    varHandle.compareAndSet(instance, a2, 1);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, Integer.valueOf(1), 2);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, Integer.valueOf(2), Integer.valueOf(3));
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, Integer.valueOf(3), 4);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, 4L, 5);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, (byte) 4, 5);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, (short) 4, 5);
+    System.out.println(varHandle.get(instance));
+
+    varHandle.compareAndSet(instance, 4, 5L);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, Long.valueOf(5), 6L);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, Long.valueOf(6), Long.valueOf(7));
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, Long.valueOf(7), 8L);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, 8, 9L);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, (byte) 8, 9);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, (short) 8, 9);
+    System.out.println(varHandle.get(instance));
+    System.out.println(varHandle.get(instance) == a1);
+    varHandle.compareAndSet(instance, a1, a2);
+    System.out.println(varHandle.get(instance));
+    System.out.println(varHandle.get(instance) == a2);
+
+    varHandle.compareAndSet(instance, a2, 1);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, Integer.valueOf(1), 2);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, Integer.valueOf(2), Integer.valueOf(3));
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, Integer.valueOf(3), 4);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, 4L, 5);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, (byte) 4, 5);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, (short) 4, 5);
+    System.out.println(varHandle.get(instance));
+
+    varHandle.compareAndSet(instance, 4, 5L);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, Long.valueOf(5), 6L);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, Long.valueOf(6), Long.valueOf(7));
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, Long.valueOf(7), 8L);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, 8, 9L);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, (byte) 8, 9);
+    System.out.println(varHandle.get(instance));
+    varHandle.compareAndSet(instance, (short) 8, 9);
+    System.out.println(varHandle.get(instance));
+  }
+
   public static void testReturnValueClassCastException(VarHandle varHandle) {
     System.out.println("testReturnValueClassCastException");
 
@@ -271,8 +629,11 @@
   public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
     VarHandle varHandle =
         MethodHandles.lookup().findVarHandle(InstanceObjectField.class, "field", Object.class);
-    testSet(varHandle);
+    testSetGet(varHandle);
+    testSetVolatileGetVolatile(varHandle);
+    testSetReleaseGet(varHandle);
     testCompareAndSet(varHandle);
+    testWeakCompareAndSet(varHandle);
     testReturnValueClassCastException(varHandle);
   }
 }
diff --git a/src/test/examplesJava9/varhandle/MethodHandlesPrivateLookupIn.java b/src/test/examplesJava9/varhandle/MethodHandlesPrivateLookupIn.java
new file mode 100644
index 0000000..1899370
--- /dev/null
+++ b/src/test/examplesJava9/varhandle/MethodHandlesPrivateLookupIn.java
@@ -0,0 +1,47 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package varhandle;
+
+import java.lang.invoke.MethodHandles;
+import varhandle.util.WithPrivateFields;
+
+public class MethodHandlesPrivateLookupIn {
+
+  public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
+    MethodHandles.Lookup lookup = MethodHandles.lookup();
+
+    WithPrivateFields withPrivateFields = new WithPrivateFields();
+    try {
+      lookup.findVarHandle(WithPrivateFields.class, "intField", int.class).get(withPrivateFields);
+      System.out.println("Unexpected success");
+    } catch (IllegalAccessException e) {
+    }
+    System.out.println(
+        MethodHandles.privateLookupIn(WithPrivateFields.class, lookup)
+            .findVarHandle(WithPrivateFields.class, "intField", int.class)
+            .get(withPrivateFields));
+
+    try {
+      lookup.findVarHandle(WithPrivateFields.class, "longField", long.class).get(withPrivateFields);
+      System.out.println("Unexpected success");
+    } catch (IllegalAccessException e) {
+    }
+    System.out.println(
+        MethodHandles.privateLookupIn(WithPrivateFields.class, lookup)
+            .findVarHandle(WithPrivateFields.class, "longField", long.class)
+            .get(withPrivateFields));
+
+    try {
+      lookup
+          .findVarHandle(WithPrivateFields.class, "referenceField", Object.class)
+          .get(withPrivateFields);
+      System.out.println("Unexpected success");
+    } catch (IllegalAccessException e) {
+    }
+    System.out.println(
+        MethodHandles.privateLookupIn(WithPrivateFields.class, lookup)
+            .findVarHandle(WithPrivateFields.class, "referenceField", Object.class)
+            .get(withPrivateFields));
+  }
+}
diff --git a/src/test/examplesJava9/varhandle/NoDesugaredTypesInSignatures.java b/src/test/examplesJava9/varhandle/NoDesugaredTypesInSignatures.java
new file mode 100644
index 0000000..0e80d0a
--- /dev/null
+++ b/src/test/examplesJava9/varhandle/NoDesugaredTypesInSignatures.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package varhandle;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+public class NoDesugaredTypesInSignatures {
+
+  private int field;
+
+  public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
+    // Code where references to VarHandle and MethodHandles$Lookup is only in code and not in any
+    // signature. javac will still add references in InnerClasses attributes.
+    VarHandle varHandle =
+        MethodHandles.lookup()
+            .findVarHandle(NoDesugaredTypesInSignatures.class, "field", int.class);
+
+    NoDesugaredTypesInSignatures instance = new NoDesugaredTypesInSignatures();
+    System.out.println((int) varHandle.get(instance));
+  }
+}
diff --git a/src/test/examplesJava9/varhandle/util/WithPrivateFields.java b/src/test/examplesJava9/varhandle/util/WithPrivateFields.java
new file mode 100644
index 0000000..2b591bb
--- /dev/null
+++ b/src/test/examplesJava9/varhandle/util/WithPrivateFields.java
@@ -0,0 +1,11 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package varhandle.util;
+
+public class WithPrivateFields {
+  private int intField;
+  private long longField;
+  private Object referenceField;
+}
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/MethodHandlesPrivateLookupInTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/MethodHandlesPrivateLookupInTest.java
new file mode 100644
index 0000000..83896c8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/MethodHandlesPrivateLookupInTest.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.cf.varhandle;
+
+import com.android.tools.r8.examples.jdk9.VarHandle;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class MethodHandlesPrivateLookupInTest extends VarHandleDesugaringTestBase {
+
+  private static final String EXPECTED_OUTPUT = StringUtils.lines("0", "0", "null");
+  private static final String MAIN_CLASS = VarHandle.MethodHandlesPrivateLookupIn.typeName();
+  private static final String JAR_ENTRY = "varhandle/MethodHandlesPrivateLookupIn.class";
+  private static final List<String> JAR_ENTRIES =
+      ImmutableList.of(
+          "varhandle/MethodHandlesPrivateLookupIn.class", "varhandle/util/WithPrivateFields.class");
+
+  @Override
+  protected String getMainClass() {
+    return MAIN_CLASS;
+  }
+
+  @Override
+  protected List<String> getKeepRules() {
+    return ImmutableList.of(
+        "-keep class " + getMainClass() + "{ <fields>; }",
+        "-keep class varhandle.util.WithPrivateFields { <fields>; }");
+  }
+
+  @Override
+  protected List<String> getJarEntries() {
+    return JAR_ENTRIES;
+  }
+
+  @Override
+  protected String getExpectedOutputForReferenceImplementation() {
+    return EXPECTED_OUTPUT;
+  }
+
+  @Override
+  protected String getExpectedOutputForDesugaringImplementation() {
+    // TODO(b/247076137): Desugar implementation allows VarHandle on private fields.
+    return StringUtils.lines(
+        "Unexpected success", "0", "Unexpected success", "0", "Unexpected success", "null");
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfIntTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfIntTest.java
index db63206..bb98312 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfIntTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfIntTest.java
@@ -14,72 +14,36 @@
 @RunWith(Parameterized.class)
 public class VarHandleDesugaringArrayOfIntTest extends VarHandleDesugaringTestBase {
 
+  private static final String TEST_GET_EXPECTED_OUTPUT =
+      StringUtils.lines("1", "2", "1", "2", "1", "2", "1", "2", "1.0", "2.0", "1.0", "2.0").trim();
+
+  private static final String TEST_SET_EXPECTED_OUTPUT =
+      StringUtils.lines(
+              "1", "0", "1", "2", "3", "2", "3", "4", "5", "4", "5", "6", "7", "6", "7", "8", "48",
+              "8", "48", "49", "50", "49", "50", "51", "9", "51", "9", "10", "11", "10", "11", "12",
+              "11", "12", "11", "12", "11", "12", "11", "12", "11", "12", "11", "12", "11", "12",
+              "11", "12", "11", "12")
+          .trim();
+
+  private static final String TEST_COMPAREANDSET_EXPECTED_OUTPUT =
+      StringUtils.lines("1", "0", "1", "0", "1", "2", "1", "3").trim();
+
   private static final String EXPECTED_OUTPUT =
       StringUtils.lines(
           "testGet",
-          "1",
-          "2",
-          "1",
-          "2",
-          "1",
-          "2",
-          "1",
-          "2",
-          "1.0",
-          "2.0",
-          "1.0",
-          "2.0",
+          TEST_GET_EXPECTED_OUTPUT,
+          "testGetVolatile",
+          TEST_GET_EXPECTED_OUTPUT,
           "testSet",
-          "1",
-          "0",
-          "1",
-          "2",
-          "3",
-          "2",
-          "3",
-          "4",
-          "5",
-          "4",
-          "5",
-          "6",
-          "7",
-          "6",
-          "7",
-          "8",
-          "48",
-          "8",
-          "48",
-          "49",
-          "50",
-          "49",
-          "50",
-          "51",
-          "9",
-          "51",
-          "9",
-          "10",
-          "11",
-          "10",
-          "11",
-          "12",
-          "11",
-          "12",
-          "11",
-          "12",
-          "11",
-          "12",
-          "11",
-          "12",
-          "11",
-          "12",
-          "11",
-          "12",
-          "11",
-          "12",
-          "11",
-          "12",
-          "11",
-          "12",
+          TEST_SET_EXPECTED_OUTPUT,
+          "testSetVolatile",
+          TEST_SET_EXPECTED_OUTPUT,
+          "testSetRelease",
+          TEST_SET_EXPECTED_OUTPUT,
+          "testCompareAndSet",
+          TEST_COMPAREANDSET_EXPECTED_OUTPUT,
+          "testWeakCompareAndSet",
+          TEST_COMPAREANDSET_EXPECTED_OUTPUT,
           "testArrayVarHandleForNonSingleDimension",
           "IllegalArgumentException");
 
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfLongTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfLongTest.java
index 3867f1c..4706835 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfLongTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfLongTest.java
@@ -14,74 +14,36 @@
 @RunWith(Parameterized.class)
 public class VarHandleDesugaringArrayOfLongTest extends VarHandleDesugaringTestBase {
 
+  private static final String TEST_GET_EXPECTED_OUTPUT =
+      StringUtils.lines("1", "2", "1", "2", "1", "2", "1.0", "2.0", "1.0", "2.0").trim();
+
+  private static final String TEST_SET_EXPECTED_OUTPUT =
+      StringUtils.lines(
+              "1", "0", "1", "2", "3", "2", "3", "4", "5", "4", "5", "6", "7", "6", "7", "8", "48",
+              "8", "48", "49", "50", "49", "50", "51", "9", "51", "9", "10", "11", "10", "11", "12",
+              "13", "12", "13", "14", "15", "14", "15", "16", "15", "16", "15", "16", "15", "16",
+              "15", "16", "15", "16", "15", "16", "15", "16")
+          .trim();
+
+  private static final String TEST_COMPAREANDSET_EXPECTED_OUTPUT =
+      StringUtils.lines("1", "0", "1", "0", "1", "2", "1", "3").trim();
+
   private static final String EXPECTED_OUTPUT =
       StringUtils.lines(
           "testGet",
-          "1",
-          "2",
-          "1",
-          "2",
-          "1",
-          "2",
-          "1.0",
-          "2.0",
-          "1.0",
-          "2.0",
+          TEST_GET_EXPECTED_OUTPUT,
+          "testGetVolatile",
+          TEST_GET_EXPECTED_OUTPUT,
           "testSet",
-          "1",
-          "0",
-          "1",
-          "2",
-          "3",
-          "2",
-          "3",
-          "4",
-          "5",
-          "4",
-          "5",
-          "6",
-          "7",
-          "6",
-          "7",
-          "8",
-          "48",
-          "8",
-          "48",
-          "49",
-          "50",
-          "49",
-          "50",
-          "51",
-          "9",
-          "51",
-          "9",
-          "10",
-          "11",
-          "10",
-          "11",
-          "12",
-          "13",
-          "12",
-          "13",
-          "14",
-          "15",
-          "14",
-          "15",
-          "16",
-          "15",
-          "16",
-          "15",
-          "16",
-          "15",
-          "16",
-          "15",
-          "16",
-          "15",
-          "16",
-          "15",
-          "16",
-          "15",
-          "16",
+          TEST_SET_EXPECTED_OUTPUT,
+          "testSetVolatile",
+          TEST_SET_EXPECTED_OUTPUT,
+          "testSetRelease",
+          TEST_SET_EXPECTED_OUTPUT,
+          "testCompareAndSet",
+          TEST_COMPAREANDSET_EXPECTED_OUTPUT,
+          "testWeakCompareAndSet",
+          TEST_COMPAREANDSET_EXPECTED_OUTPUT,
           "testArrayVarHandleForNonSingleDimension",
           "IllegalArgumentException");
 
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfObjectTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfObjectTest.java
index 72439ec..b06abad 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfObjectTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfObjectTest.java
@@ -14,109 +14,43 @@
 @RunWith(Parameterized.class)
 public class VarHandleDesugaringArrayOfObjectTest extends VarHandleDesugaringTestBase {
 
+  private static final String TEST_GET_EXPECTED_OUTPUT =
+      StringUtils.lines(
+              "1", "2", "1", "2", "1", "2", "1", "2", "1.0", "2.0", "1.0", "2.0", "3", "4", "3",
+              "4", "3", "4", "3.0", "4.0", "3.0", "4.0")
+          .trim();
+
+  private static final String TEST_SET_EXPECTED_OUTPUT =
+      StringUtils.lines(
+              "5", "5", "true", "true", "6", "6", "true", "true", "7", "7", "true", "true", "8",
+              "8", "true", "true", "9.0", "9.0", "true", "true", "10.0", "10.0", "true", "true",
+              "11.0", "11.0", "true", "true", "12.0", "12.0", "true", "true", "A", "A", "true",
+              "true", "B", "B", "true", "true")
+          .trim();
+
+  private static final String TEST_COMPAREANDSET_EXPECTED_OUTPUT =
+      StringUtils.lines(
+              "null", "A(1)", "true", "A(2)", "true", "1", "2", "3", "4", "4", "4", "4", "5", "6",
+              "7", "8", "8", "8", "8", "false", "8", "false", "8", "8", "8", "8", "8", "8", "8",
+              "8", "8", "8", "8", "8", "8", "8")
+          .trim();
+
   private static final String EXPECTED_OUTPUT =
       StringUtils.lines(
           "testGet",
-          "1",
-          "2",
-          "1",
-          "2",
-          "1",
-          "2",
-          "1",
-          "2",
-          "1.0",
-          "2.0",
-          "1.0",
-          "2.0",
-          "3",
-          "4",
-          "3",
-          "4",
-          "3",
-          "4",
-          "3.0",
-          "4.0",
-          "3.0",
-          "4.0",
+          TEST_GET_EXPECTED_OUTPUT,
+          "testGetVolatile",
+          TEST_GET_EXPECTED_OUTPUT,
           "testSet",
-          "5",
-          "5",
-          "true",
-          "true",
-          "6",
-          "6",
-          "true",
-          "true",
-          "7",
-          "7",
-          "true",
-          "true",
-          "8",
-          "8",
-          "true",
-          "true",
-          "9.0",
-          "9.0",
-          "true",
-          "true",
-          "10.0",
-          "10.0",
-          "true",
-          "true",
-          "11.0",
-          "11.0",
-          "true",
-          "true",
-          "12.0",
-          "12.0",
-          "true",
-          "true",
-          "A",
-          "A",
-          "true",
-          "true",
-          "B",
-          "B",
-          "true",
-          "true",
+          TEST_SET_EXPECTED_OUTPUT,
+          "testSetVolatile",
+          TEST_SET_EXPECTED_OUTPUT,
+          "testSetRelease",
+          TEST_SET_EXPECTED_OUTPUT,
           "testCompareAndSet",
-          "null",
-          "A(1)",
-          "true",
-          "A(2)",
-          "true",
-          "1",
-          "2",
-          "3",
-          "4",
-          "4",
-          "4",
-          "4",
-          "5",
-          "6",
-          "7",
-          "8",
-          "8",
-          "8",
-          "8",
-          "false",
-          "8",
-          "false",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
+          TEST_COMPAREANDSET_EXPECTED_OUTPUT,
+          "testWeakCompareAndSet",
+          TEST_COMPAREANDSET_EXPECTED_OUTPUT,
           "testArrayVarHandleForNonSingleDimension",
           "IllegalArgumentException");
 
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceBooleanFieldTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceBooleanFieldTest.java
index 5c84a74..c1e41d2 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceBooleanFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceBooleanFieldTest.java
@@ -36,8 +36,8 @@
   }
 
   @Override
-  protected String getKeepRules() {
-    return "-keep class " + getMainClass() + "{ <fields>; }";
+  protected List<String> getKeepRules() {
+    return ImmutableList.of("-keep class " + getMainClass() + "{ <fields>; }");
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceByteFieldTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceByteFieldTest.java
index a2f3b1d..2263de1 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceByteFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceByteFieldTest.java
@@ -26,8 +26,8 @@
   }
 
   @Override
-  protected String getKeepRules() {
-    return "-keep class " + getMainClass() + "{ <fields>; }";
+  protected List<String> getKeepRules() {
+    return ImmutableList.of("-keep class " + getMainClass() + "{ <fields>; }");
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceDoubleFieldTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceDoubleFieldTest.java
index 9eccf94..019e556 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceDoubleFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceDoubleFieldTest.java
@@ -27,8 +27,8 @@
   }
 
   @Override
-  protected String getKeepRules() {
-    return "-keep class " + getMainClass() + "{ <fields>; }";
+  protected List<String> getKeepRules() {
+    return ImmutableList.of("-keep class " + getMainClass() + "{ <fields>; }");
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceFloatFieldTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceFloatFieldTest.java
index db95c14..13e23b6 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceFloatFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceFloatFieldTest.java
@@ -27,8 +27,8 @@
   }
 
   @Override
-  protected String getKeepRules() {
-    return "-keep class " + getMainClass() + "{ <fields>; }";
+  protected List<String> getKeepRules() {
+    return ImmutableList.of("-keep class " + getMainClass() + "{ <fields>; }");
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceIntFieldTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceIntFieldTest.java
index 1969ffb..9de3a8c 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceIntFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceIntFieldTest.java
@@ -14,63 +14,37 @@
 @RunWith(Parameterized.class)
 public class VarHandleDesugaringInstanceIntFieldTest extends VarHandleDesugaringTestBase {
 
+  private static final String TEST_GET_EXPECTED_OUTPUT =
+      StringUtils.lines("1", "1", "1", "1", "1.0", "1.0").trim();
+
+  private static final String TEST_SET_EXPECTED_OUTPUT =
+      StringUtils.lines("0", "1", "2", "3", "4", "48", "49", "5", "6", "6", "6", "6", "6", "6", "6")
+          .trim();
+
+  private static final String TEST_COMPAREANDSET_EXPECTED_OUTPUT =
+      StringUtils.lines(
+              "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "48", "49", "50", "51", "52",
+              "53", "53", "53", "53", "53", "53", "53", "53", "53", "53", "53", "53", "53", "53",
+              "53")
+          .trim();
+
   private static final String EXPECTED_OUTPUT =
       StringUtils.lines(
           "testGet",
-          "1",
-          "1",
-          "1",
-          "1",
-          "1.0",
-          "1.0",
+          TEST_GET_EXPECTED_OUTPUT,
+          "testGetVolatile",
+          TEST_GET_EXPECTED_OUTPUT,
           "testSet",
-          "0",
-          "1",
-          "2",
-          "3",
-          "4",
-          "48",
-          "49",
-          "5",
-          "6",
-          "6",
-          "6",
-          "6",
-          "6",
-          "6",
-          "6",
+          TEST_SET_EXPECTED_OUTPUT,
+          "testSetVolatile",
+          TEST_SET_EXPECTED_OUTPUT,
+          "testSetRelease",
+          TEST_SET_EXPECTED_OUTPUT,
           "testCompareAndSet",
-          "0",
-          "1",
-          "2",
-          "3",
-          "4",
-          "5",
-          "6",
-          "7",
-          "8",
-          "9",
-          "10",
-          "48",
-          "49",
-          "50",
-          "51",
-          "52",
-          "53",
-          "53",
-          "53",
-          "53",
-          "53",
-          "53",
-          "53",
-          "53",
-          "53",
-          "53",
-          "53",
-          "53",
-          "53",
-          "53",
-          "53");
+          TEST_COMPAREANDSET_EXPECTED_OUTPUT,
+          "testWeakCompareAndSet",
+          TEST_COMPAREANDSET_EXPECTED_OUTPUT);
+
   private static final String MAIN_CLASS = VarHandle.InstanceIntField.typeName();
   private static final String JAR_ENTRY = "varhandle/InstanceIntField.class";
 
@@ -80,8 +54,8 @@
   }
 
   @Override
-  protected String getKeepRules() {
-    return "-keep class " + getMainClass() + "{ <fields>; }";
+  protected List<String> getKeepRules() {
+    return ImmutableList.of("-keep class " + getMainClass() + "{ <fields>; }");
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceLongFieldTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceLongFieldTest.java
index 9794153..2196b35 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceLongFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceLongFieldTest.java
@@ -14,61 +14,36 @@
 @RunWith(Parameterized.class)
 public class VarHandleDesugaringInstanceLongFieldTest extends VarHandleDesugaringTestBase {
 
+  private static final String TEST_GET_EXPECTED_OUTPUT =
+      StringUtils.lines("1", "1", "1", "1.0", "1.0").trim();
+
+  private static final String TEST_SET_EXPECTED_OUTPUT =
+      StringUtils.lines("0", "1", "2", "3", "4", "48", "49", "5", "6", "7", "8", "8", "8", "8", "8")
+          .trim();
+
+  private static final String TEST_COMPAREANDSET_EXPECTED_OUTPUT =
+      StringUtils.lines(
+              "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "48", "49", "50", "51", "52",
+              "53", "11", "12", "13", "14", "14", "14", "14", "14", "14", "14", "14", "14", "14")
+          .trim();
+
   private static final String EXPECTED_OUTPUT =
       StringUtils.lines(
           "testGet",
-          "1",
-          "1",
-          "1",
-          "1.0",
-          "1.0",
+          TEST_GET_EXPECTED_OUTPUT,
+          "testGetVolatile",
+          TEST_GET_EXPECTED_OUTPUT,
           "testSet",
-          "0",
-          "1",
-          "2",
-          "3",
-          "4",
-          "48",
-          "49",
-          "5",
-          "6",
-          "7",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
+          TEST_SET_EXPECTED_OUTPUT,
+          "testSetVolatile",
+          TEST_SET_EXPECTED_OUTPUT,
+          "testSetRelease",
+          TEST_SET_EXPECTED_OUTPUT,
           "testCompareAndSet",
-          "0",
-          "1",
-          "2",
-          "3",
-          "4",
-          "5",
-          "6",
-          "7",
-          "8",
-          "9",
-          "10",
-          "48",
-          "49",
-          "50",
-          "51",
-          "52",
-          "53",
-          "11",
-          "12",
-          "13",
-          "14",
-          "14",
-          "14",
-          "14",
-          "14",
-          "14",
-          "14",
-          "14",
-          "14",
-          "14");
+          TEST_COMPAREANDSET_EXPECTED_OUTPUT,
+          "testWeakCompareAndSet",
+          TEST_COMPAREANDSET_EXPECTED_OUTPUT);
+
   private static final String MAIN_CLASS = VarHandle.InstanceLongField.typeName();
   private static final String JAR_ENTRY = "varhandle/InstanceLongField.class";
 
@@ -78,8 +53,8 @@
   }
 
   @Override
-  protected String getKeepRules() {
-    return "-keep class " + getMainClass() + "{ <fields>; }";
+  protected List<String> getKeepRules() {
+    return ImmutableList.of("-keep class " + getMainClass() + "{ <fields>; }");
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceObjectFieldTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceObjectFieldTest.java
index a7b2a30..2673e46 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceObjectFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceObjectFieldTest.java
@@ -14,108 +14,36 @@
 @RunWith(Parameterized.class)
 public class VarHandleDesugaringInstanceObjectFieldTest extends VarHandleDesugaringTestBase {
 
+  private static final String TEST_GET_SET_EXPECTED_OUTPUT =
+      StringUtils.lines(
+              "null", "A(1)", "true", "A(2)", "true", "1", "1", "true", "true", "2", "2", "true",
+              "true", "3", "3", "true", "true", "4", "4", "true", "true", "5", "5", "true", "true",
+              "6", "6", "true", "true", "7", "7", "true", "true", "8", "8", "true", "true", "9.0",
+              "9.0", "true", "true", "10.0", "10.0", "true", "true", "11.0", "11.0", "true", "true",
+              "12.0", "12.0", "true", "true", "A", "A", "true", "true", "B", "B", "true", "true")
+          .trim();
+
+  private static final String TEST_COMPAREANDSET_EXPECTED_OUTPUT =
+      StringUtils.lines(
+              "null", "A(1)", "true", "A(2)", "true", "1", "2", "3", "4", "4", "4", "4", "5", "6",
+              "7", "8", "8", "8", "8", "false", "8", "false", "8", "8", "8", "8", "8", "8", "8",
+              "8", "8", "8", "8", "8", "8", "8")
+          .trim();
+
   private static final String EXPECTED_OUTPUT =
       StringUtils.lines(
-          "testSet",
-          "null",
-          "A(1)",
-          "true",
-          "A(2)",
-          "true",
-          "1",
-          "1",
-          "true",
-          "true",
-          "2",
-          "2",
-          "true",
-          "true",
-          "3",
-          "3",
-          "true",
-          "true",
-          "4",
-          "4",
-          "true",
-          "true",
-          "5",
-          "5",
-          "true",
-          "true",
-          "6",
-          "6",
-          "true",
-          "true",
-          "7",
-          "7",
-          "true",
-          "true",
-          "8",
-          "8",
-          "true",
-          "true",
-          "9.0",
-          "9.0",
-          "true",
-          "true",
-          "10.0",
-          "10.0",
-          "true",
-          "true",
-          "11.0",
-          "11.0",
-          "true",
-          "true",
-          "12.0",
-          "12.0",
-          "true",
-          "true",
-          "A",
-          "A",
-          "true",
-          "true",
-          "B",
-          "B",
-          "true",
-          "true",
+          "testSetGet",
+          TEST_GET_SET_EXPECTED_OUTPUT,
+          "testSetVolatileGetVolatile",
+          TEST_GET_SET_EXPECTED_OUTPUT,
+          "testSetReleaseGet",
+          TEST_GET_SET_EXPECTED_OUTPUT,
           "testCompareAndSet",
-          "null",
-          "A(1)",
-          "true",
-          "A(2)",
-          "true",
-          "1",
-          "2",
-          "3",
-          "4",
-          "4",
-          "4",
-          "4",
-          "5",
-          "6",
-          "7",
-          "8",
-          "8",
-          "8",
-          "8",
-          "false",
-          "8",
-          "false",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
-          "8",
+          TEST_COMPAREANDSET_EXPECTED_OUTPUT,
+          "testWeakCompareAndSet",
+          TEST_COMPAREANDSET_EXPECTED_OUTPUT,
           "testReturnValueClassCastException");
+
   private static final String MAIN_CLASS = VarHandle.InstanceObjectField.typeName();
   private static final List<String> JAR_ENTRIES =
       ImmutableList.of(
@@ -127,8 +55,8 @@
   }
 
   @Override
-  protected String getKeepRules() {
-    return "-keep class " + getMainClass() + "{ <fields>; }";
+  protected List<String> getKeepRules() {
+    return ImmutableList.of("-keep class " + getMainClass() + "{ <fields>; }");
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceShortFieldTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceShortFieldTest.java
index e52df14..60d4cb9 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceShortFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceShortFieldTest.java
@@ -26,8 +26,8 @@
   }
 
   @Override
-  protected String getKeepRules() {
-    return "-keep class " + getMainClass() + "{ <fields>; }";
+  protected List<String> getKeepRules() {
+    return ImmutableList.of("-keep class " + getMainClass() + "{ <fields>; }");
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceStringFieldTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceStringFieldTest.java
index e1beca1..d2affd1 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceStringFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringInstanceStringFieldTest.java
@@ -37,8 +37,8 @@
   }
 
   @Override
-  protected String getKeepRules() {
-    return "-keep class " + getMainClass() + "{ <fields>; }";
+  protected List<String> getKeepRules() {
+    return ImmutableList.of("-keep class " + getMainClass() + "{ <fields>; }");
   }
 
   @Override
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringTestBase.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringTestBase.java
index d8b0543..833e949 100644
--- a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringTestBase.java
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringTestBase.java
@@ -10,7 +10,6 @@
 import static org.junit.Assume.assumeTrue;
 
 import com.android.tools.r8.JdkClassFileProvider;
-import com.android.tools.r8.R8TestBuilder;
 import com.android.tools.r8.TestBase;
 import com.android.tools.r8.TestParameters;
 import com.android.tools.r8.TestParametersCollection;
@@ -56,8 +55,8 @@
 
   protected abstract String getMainClass();
 
-  protected String getKeepRules() {
-    return "";
+  protected List<String> getKeepRules() {
+    return ImmutableList.of("");
   }
 
   protected abstract List<String> getJarEntries();
@@ -74,7 +73,10 @@
 
   @Test
   public void testReference() throws Throwable {
-    assumeTrue(parameters.isCfRuntime());
+    // The tests for weakCompareAndSet might fail on the JVM, as the tests do not account for
+    // possible spurious failures but expect it to behave like compareAndSet (which is what the
+    // desugared implementation does.
+    assumeTrue(parameters.isCfRuntime() && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK9));
     testForJvm()
         .addProgramFiles(VarHandle.jar())
         .run(parameters.getRuntime(), getMainClass())
@@ -163,8 +165,8 @@
               });
         });
     if (willDesugarVarHandle()) {
-      assertEquals(4, unsafeCompareAndSwapInt.get());
-      assertEquals(5, unsafeCompareAndSwapLong.get());
+      assertEquals(8, unsafeCompareAndSwapInt.get());
+      assertEquals(10, unsafeCompareAndSwapLong.get());
       assertEquals(1, unsafeCompareAndSwapObject.get());
     } else {
       assertEquals(0, unsafeCompareAndSwapInt.get());
@@ -197,21 +199,8 @@
         .inspect(this::inspect);
   }
 
-  // TODO(b/247076137: Also turn on VarHandle desugaring for R8 tests.
   @Test
   public void testR8() throws Throwable {
-    // TODO(b/247076137: The "default" VM is acting up on some tests - skip these as they will
-    // be fixed when VarHandle desugaring is enabled for R8.
-    if (parameters.isDexRuntime()
-        && parameters.asDexRuntime().getVersion().isEqualTo(Version.DEFAULT)
-        && parameters.getApiLevel().equals(AndroidApiLevel.B)
-        && (this instanceof VarHandleDesugaringInstanceBooleanFieldTest
-            || this instanceof VarHandleDesugaringInstanceByteFieldTest
-            || this instanceof VarHandleDesugaringInstanceShortFieldTest
-            || this instanceof VarHandleDesugaringInstanceFloatFieldTest
-            || this instanceof VarHandleDesugaringInstanceDoubleFieldTest)) {
-      return;
-    }
     testForR8(parameters.getBackend())
         .applyIf(
             parameters.isDexRuntime(),
@@ -220,26 +209,25 @@
             // Use system JDK to have references types including StringConcatFactory.
             b -> b.addLibraryProvider(JdkClassFileProvider.fromSystemJdk()))
         .addProgramClassFileData(getProgramClassFileData())
+        .addOptionsModification(options -> options.enableVarHandleDesugaring = true)
         .setMinApi(parameters.getApiLevel())
         .addKeepMainRule(getMainClass())
         .addKeepRules(getKeepRules())
-        .applyIf(
-            parameters.isDexRuntime() && parameters.getApiLevel().isLessThan(AndroidApiLevel.O),
-            R8TestBuilder::allowDiagnosticWarningMessages)
         .run(parameters.getRuntime(), getMainClass())
         .applyIf(
-            // VarHandle is available from Android 9, even though it was not a public API until 13.
             parameters.isDexRuntime()
-                && parameters.asDexRuntime().getVersion().isOlderThanOrEqual(Version.V7_0_0),
-            r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class),
-            parameters.isDexRuntime()
-                && (parameters.getApiLevel().isLessThan(AndroidApiLevel.P)
-                    || parameters.asDexRuntime().getVersion().isOlderThanOrEqual(Version.V8_1_0)),
-            r -> r.assertFailure(),
+                && parameters.asDexRuntime().getVersion().isOlderThanOrEqual(Version.V4_4_4),
+            // TODO(b/247076137): Running on 4.0.4 and 4.4.4 needs to be checked. Output seems
+            // correct, but at the same time there are VFY errors on stderr.
+            r -> r.assertFailureWithErrorThatThrows(NoSuchFieldException.class),
             r ->
                 r.assertSuccessWithOutput(
-                    parameters.isCfRuntime()
-                        ? getExpectedOutputForReferenceImplementation()
-                        : getExpectedOutputForArtImplementation()));
+                    parameters.isDexRuntime()
+                            && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.T)
+                            && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V13_0_0)
+                        ? getExpectedOutputForArtImplementation()
+                        : (parameters.isDexRuntime()
+                            ? getExpectedOutputForDesugaringImplementation()
+                            : getExpectedOutputForReferenceImplementation())));
   }
 }
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleNoDesugaredTypesInSignaturesNoAttributesTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleNoDesugaredTypesInSignaturesNoAttributesTest.java
new file mode 100644
index 0000000..872febb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleNoDesugaredTypesInSignaturesNoAttributesTest.java
@@ -0,0 +1,88 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.cf.varhandle;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.JdkClassFileProvider;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.examples.jdk9.VarHandle;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.ZipUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class VarHandleNoDesugaredTypesInSignaturesNoAttributesTest extends TestBase {
+
+  private static final String EXPECTED_OUTPUT = StringUtils.lines("0");
+  private static final String MAIN_CLASS = VarHandle.NoDesugaredTypesInSignatures.typeName();
+  private static final String JAR_ENTRY = "varhandle/NoDesugaredTypesInSignatures.class";
+
+  @Parameter(0)
+  public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters()
+        .withCfRuntimesStartingFromIncluding(CfVm.JDK9)
+        // Running on 4.0.4 and 4.4.4 needs to be checked. Output seems correct, but at the
+        // same time there are VFY errors on stderr.
+        .withDexRuntimesStartingFromExcluding(Version.V4_4_4)
+        .withAllApiLevels()
+        .build();
+  }
+
+  @Test
+  public void testR8() throws Throwable {
+    // Strip the attributes (including InnerClasses) to ensure that the enqueuer does not
+    // register references to MethodHandles$Lookup until the desugar step.
+    Path programWithoutAttributes =
+        testForR8(Backend.CF)
+            .addLibraryProvider(JdkClassFileProvider.fromSystemJdk())
+            .addProgramClassFileData(ZipUtils.readSingleEntry(VarHandle.jar(), JAR_ENTRY))
+            .addKeepClassAndMembersRules(MAIN_CLASS)
+            .compile()
+            .writeToZip();
+    assertTrue(
+        new CodeInspector(programWithoutAttributes)
+            .clazz(MAIN_CLASS)
+            .getDexProgramClass()
+            .getInnerClasses()
+            .isEmpty());
+
+    testForR8(parameters.getBackend())
+        .applyIf(
+            parameters.isDexRuntime(),
+            // Use android.jar from Android T to get the VarHandle type.
+            b -> b.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T)),
+            // Use system JDK to have references types including StringConcatFactory.
+            b -> b.addLibraryProvider(JdkClassFileProvider.fromSystemJdk()))
+        .addProgramFiles(programWithoutAttributes)
+        .addOptionsModification(options -> options.enableVarHandleDesugaring = true)
+        .setMinApi(parameters.getApiLevel())
+        .addKeepMainRule(MAIN_CLASS)
+        .addKeepRules("-keep class " + MAIN_CLASS + "{ <fields>; }")
+        .run(parameters.getRuntime(), MAIN_CLASS)
+        .applyIf(
+            parameters.isDexRuntime()
+                && parameters.asDexRuntime().getVersion().isOlderThanOrEqual(Version.V4_4_4),
+            // TODO(b/247076137): Running on 4.0.4 and 4.4.4 needs to be checked. Output seems
+            // correct, but at the same time there are VFY errors on stderr.
+            r -> r.assertFailureWithErrorThatThrows(NoSuchFieldException.class),
+            r -> r.assertSuccessWithOutput(EXPECTED_OUTPUT));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleNoDesugaredTypesInSignaturesTest.java b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleNoDesugaredTypesInSignaturesTest.java
new file mode 100644
index 0000000..096fda3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleNoDesugaredTypesInSignaturesTest.java
@@ -0,0 +1,40 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.cf.varhandle;
+
+import com.android.tools.r8.examples.jdk9.VarHandle;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class VarHandleNoDesugaredTypesInSignaturesTest extends VarHandleDesugaringTestBase {
+
+  private static final String EXPECTED_OUTPUT = StringUtils.lines("0");
+  private static final String MAIN_CLASS = VarHandle.NoDesugaredTypesInSignatures.typeName();
+  private static final String JAR_ENTRY = "varhandle/NoDesugaredTypesInSignatures.class";
+
+  @Override
+  protected String getMainClass() {
+    return MAIN_CLASS;
+  }
+
+  @Override
+  protected List<String> getKeepRules() {
+    return ImmutableList.of("-keep class " + getMainClass() + "{ <fields>; }");
+  }
+
+  @Override
+  protected List<String> getJarEntries() {
+    return ImmutableList.of(JAR_ENTRY);
+  }
+
+  @Override
+  protected String getExpectedOutputForReferenceImplementation() {
+    return EXPECTED_OUTPUT;
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentLinkedQueueTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentLinkedQueueTests.java
new file mode 100644
index 0000000..a711203
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11ConcurrentLinkedQueueTests.java
@@ -0,0 +1,159 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary.jdktests;
+
+import static com.android.tools.r8.ToolHelper.JDK_TESTS_BUILD_DIR;
+import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11SupportFiles.testNGSupportProgramFiles;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_MINIMAL;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11_PATH;
+import static com.android.tools.r8.utils.FileUtils.CLASS_EXTENSION;
+import static com.android.tools.r8.utils.FileUtils.JAVA_EXTENSION;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.SingleTestRunResult;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.DesugaredLibraryTestCompileResult;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.List;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class Jdk11ConcurrentLinkedQueueTests extends DesugaredLibraryTestBase {
+
+  private static final String WHITEBOX = "WhiteBox";
+
+  private static Path[] JDK_11_CONCURRENT_LINKED_QUEUE_TEST_CLASS_FILES;
+
+  // JDK 11 test constants.
+  private static final Path JDK_11_CONCURRENT_LINKED_QUEUE_JAVA_DIR =
+      Paths.get(ToolHelper.JDK_11_TESTS_DIR + "java/util/concurrent/ConcurrentLinkedQueue");
+  private static final Path[] JDK_11_CONCURRENT_LINKED_QUEUE_JAVA_FILES =
+      new Path[] {JDK_11_CONCURRENT_LINKED_QUEUE_JAVA_DIR.resolve(WHITEBOX + JAVA_EXTENSION)};
+
+  @Parameter(0)
+  public static TestParameters parameters;
+
+  @Parameter(1)
+  public static LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+  @Parameter(2)
+  public static CompilationSpecification compilationSpecification;
+
+  @Parameters(name = "{0}, spec: {1}, {2}")
+  public static List<Object[]> data() {
+    return buildParameters(
+        // TODO(134732760): Support Dalvik VMs, currently fails because libjavacrypto is required
+        // and present only in ART runtimes.
+        getTestParameters()
+            .withDexRuntimesStartingFromIncluding(Version.V5_1_1)
+            .withAllApiLevels()
+            .withApiLevel(AndroidApiLevel.N)
+            .build(),
+        ImmutableList.of(JDK11_MINIMAL, JDK11, JDK11_PATH),
+        ImmutableList.of(D8_L8DEBUG, D8_L8SHRINK));
+  }
+
+  @BeforeClass
+  public static void compileConcurrentLinkedQueueClasses() throws Exception {
+    // Build test constants.
+    Path jdk11MathTestsDir = getStaticTemp().newFolder("ConcurrentLinkedQueue").toPath();
+    javac(TestRuntime.getCheckedInJdk11(), getStaticTemp())
+        .addClasspathFiles(
+            Collections.singletonList(Paths.get(JDK_TESTS_BUILD_DIR + "testng-6.10.jar")))
+        .addSourceFiles(JDK_11_CONCURRENT_LINKED_QUEUE_JAVA_FILES)
+        .setOutputPath(jdk11MathTestsDir)
+        .compile();
+    JDK_11_CONCURRENT_LINKED_QUEUE_TEST_CLASS_FILES =
+        new Path[] {jdk11MathTestsDir.resolve(WHITEBOX + CLASS_EXTENSION)};
+  }
+
+  private static void ranWithSuccessOrFailures(String testName, SingleTestRunResult result) {
+    // Tests use ThreadLocalRandom, so success or failure is random. Note this is only for
+    // VMs where the internal implementation is not based on JDK11.
+    assertTrue(
+        result.getStdOut().contains(StringUtils.lines(testName + ": SUCCESS"))
+            || result
+                .getStdOut()
+                .contains(StringUtils.lines("Tests result in " + testName + ": FAILURE")));
+    if (result.getStdOut().contains(StringUtils.lines(testName + ": SUCCESS"))) {
+      assertTrue(
+          result.toString(),
+          result.getStdOut().contains("Total tests run: 37, Failures: 0, Skips: 0"));
+    } else {
+      assertTrue(
+          result.toString(),
+          result.getStdOut().contains("Total tests run: 37, Failures: 1, Skips: 0")
+              || result.getStdOut().contains("Total tests run: 37, Failures: 2, Skips: 0")
+              || result.getStdOut().contains("Total tests run: 37, Failures: 3, Skips: 0")
+              || result.getStdOut().contains("Total tests run: 37, Failures: 4, Skips: 0")
+              || result.getStdOut().contains("Total tests run: 37, Failures: 5, Skips: 0")
+              || result.getStdOut().contains("Total tests run: 37, Failures: 6, Skips: 0")
+              || result.getStdOut().contains("Total tests run: 37, Failures: 7, Skips: 0")
+              || result.getStdOut().contains("Total tests run: 37, Failures: 8, Skips: 0"));
+    }
+  }
+
+  void runTest(List<String> toRun) throws Exception {
+    String verbosity = "2";
+    DesugaredLibraryTestCompileResult<?> compileResult =
+        testForDesugaredLibrary(
+                parameters, libraryDesugaringSpecification, compilationSpecification)
+            .addProgramFiles(JDK_11_CONCURRENT_LINKED_QUEUE_TEST_CLASS_FILES)
+            .addProgramFiles(testNGSupportProgramFiles())
+            // The WhiteBox test is using VarHandle and MethodHandles.privateLookupIn to inspect the
+            // internal state of the implementation, so desugaring is needed for the program here.
+            .addOptionsModification(options -> options.enableVarHandleDesugaring = true)
+            .compile()
+            .withArt6Plus64BitsLib();
+    for (String success : toRun) {
+      SingleTestRunResult<?> result =
+          compileResult.run(parameters.getRuntime(), "TestNGMainRunner", verbosity, success);
+      if ((parameters.asDexRuntime().getVersion().equals(Version.V5_1_1)
+              || parameters.asDexRuntime().getVersion().equals(Version.V6_0_1))
+          && libraryDesugaringSpecification == JDK11_MINIMAL) {
+        // Some tests use streams, so which is not desugared with JDK11_MINIMAL. These tests are
+        // somehow skipped by the test runner used in the JDK11 tests.
+        assertTrue(result.getStdOut().contains("Total tests run: 9, Failures: 0, Skips: 7"));
+        assertTrue(result.getStdOut().contains(StringUtils.lines(success + ": SUCCESS")));
+      } else if (parameters.asDexRuntime().getVersion().isOlderThanOrEqual(Version.V12_0_0)) {
+        ranWithSuccessOrFailures(success, result);
+      } else {
+        assertTrue(parameters.asDexRuntime().getVersion().isNewerThanOrEqual(Version.V13_0_0));
+        if (parameters.getApiLevel() == AndroidApiLevel.B) {
+          ranWithSuccessOrFailures(success, result);
+        } else {
+          // No desugaring and JDK11 based runtime implementation.
+          assertTrue(
+              "Failure in " + success + "\n" + result,
+              result.getStdOut().contains(StringUtils.lines(success + ": SUCCESS")));
+        }
+      }
+    }
+  }
+
+  @Test
+  public void testWhiteBox() throws Exception {
+    runTest(ImmutableList.of("WhiteBox"));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
index a66e6b4..53ffbd1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
@@ -36,7 +36,6 @@
 import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.HumanToMachineSpecificationConverter;
 import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.LegacyToHumanSpecificationConverter;
 import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.synthesis.SyntheticNaming;
 import com.android.tools.r8.utils.AndroidApiLevel;
 import com.android.tools.r8.utils.Box;
 import com.android.tools.r8.utils.InternalOptions;
@@ -102,11 +101,7 @@
 
     MachineDesugaredLibrarySpecification machineSpecParsed =
         new MachineDesugaredLibrarySpecificationParser(
-                options.dexItemFactory(),
-                options.reporter,
-                true,
-                AndroidApiLevel.B.getLevel(),
-                new SyntheticNaming())
+                options.dexItemFactory(), options.reporter, true, AndroidApiLevel.B.getLevel())
             .parse(StringResource.fromString(json2.get(), Origin.unknown()));
     assertFalse(machineSpecParsed.getRewriteType().isEmpty());
   }
@@ -129,22 +124,6 @@
     InternalOptions options = new InternalOptions();
 
     Path output = temp.newFile().toPath();
-    convertMultiLevelAnythingToMachineSpecification(spec, output, options);
-
-    MachineDesugaredLibrarySpecification machineSpecParsed =
-        new MachineDesugaredLibrarySpecificationParser(
-                options.dexItemFactory(),
-                options.reporter,
-                true,
-                AndroidApiLevel.B.getLevel(),
-                new SyntheticNaming())
-            .parse(StringResource.fromFile(output));
-    assertFalse(machineSpecParsed.getRewriteType().isEmpty());
-  }
-
-  public void convertMultiLevelAnythingToMachineSpecification(
-      LibraryDesugaringSpecification spec, Path output, InternalOptions options)
-      throws IOException {
 
     MultiAPILevelHumanDesugaredLibrarySpecification humanSpec =
         DesugaredLibraryConverter.convertMultiLevelAnythingToMachineSpecification(
@@ -154,6 +133,12 @@
             output,
             options);
 
+    MachineDesugaredLibrarySpecification machineSpecParsed =
+        new MachineDesugaredLibrarySpecificationParser(
+                options.dexItemFactory(), options.reporter, true, AndroidApiLevel.B.getLevel())
+            .parse(StringResource.fromFile(output));
+    assertFalse(machineSpecParsed.getRewriteType().isEmpty());
+
     if (humanSpec == null) {
       return;
     }
@@ -167,6 +152,19 @@
                 options.dexItemFactory(), options.reporter)
             .parseMultiLevelConfiguration(StringResource.fromString(json.get(), Origin.unknown()));
     assertSpecEquals(humanSpec, writtenHumanSpec);
+
+    // Validate converted machine spec is identical to the written one.
+    HumanDesugaredLibrarySpecification humanSimpleSpec =
+        new HumanDesugaredLibrarySpecificationParser(
+                options.dexItemFactory(), options.reporter, true, AndroidApiLevel.B.getLevel())
+            .parse(StringResource.fromString(json.get(), Origin.unknown()));
+    HumanToMachineSpecificationConverter converter =
+        new HumanToMachineSpecificationConverter(Timing.empty());
+    DexApplication app = spec.getAppForTesting(options, true);
+    MachineDesugaredLibrarySpecification machineSimpleSpec =
+        converter.convert(humanSimpleSpec, app);
+
+    assertSpecEquals(machineSimpleSpec, machineSpecParsed);
   }
 
   @Test
@@ -196,11 +194,7 @@
         new AndroidApiLevel[] {AndroidApiLevel.B, AndroidApiLevel.N, AndroidApiLevel.O}) {
       MachineDesugaredLibrarySpecification machineSpecParsed =
           new MachineDesugaredLibrarySpecificationParser(
-                  options.dexItemFactory(),
-                  options.reporter,
-                  true,
-                  api.getLevel(),
-                  new SyntheticNaming())
+                  options.dexItemFactory(), options.reporter, true, api.getLevel())
               .parse(StringResource.fromString(json2.get(), Origin.unknown()));
 
       HumanDesugaredLibrarySpecification humanSpecB =
diff --git a/src/test/java/com/android/tools/r8/examples/jdk9/VarHandle.java b/src/test/java/com/android/tools/r8/examples/jdk9/VarHandle.java
index cb2caed..9de7733 100644
--- a/src/test/java/com/android/tools/r8/examples/jdk9/VarHandle.java
+++ b/src/test/java/com/android/tools/r8/examples/jdk9/VarHandle.java
@@ -52,6 +52,12 @@
   public static final JavaExampleClassProxy InstanceStringField =
       new JavaExampleClassProxy(EXAMPLE_FILE, "varhandle/InstanceStringField");
 
+  public static final JavaExampleClassProxy NoDesugaredTypesInSignatures =
+      new JavaExampleClassProxy(EXAMPLE_FILE, "varhandle/NoDesugaredTypesInSignatures");
+
+  public static final JavaExampleClassProxy MethodHandlesPrivateLookupIn =
+      new JavaExampleClassProxy(EXAMPLE_FILE, "varhandle/MethodHandlesPrivateLookupIn");
+
   public static Path jar() {
     return JavaExampleClassProxy.examplesJar(EXAMPLE_FILE);
   }
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/varhandle/DesugarMethodHandlesLookup.java b/src/test/java/com/android/tools/r8/ir/desugar/varhandle/DesugarMethodHandlesLookup.java
index d700033..92c85c9 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/varhandle/DesugarMethodHandlesLookup.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/varhandle/DesugarMethodHandlesLookup.java
@@ -10,6 +10,10 @@
     return new DesugarVarHandle(recv, name, type);
   }
 
+  // Emulation of MethodHandled.privateLookupIn
+  public DesugarMethodHandlesLookup toPrivateLookupIn(Class<?> targetClass) {
+    return this;
+  }
   /*
    * Remaining methods on MethodHandles.Lookup.
    *
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/varhandle/DesugarVarHandle.java b/src/test/java/com/android/tools/r8/ir/desugar/varhandle/DesugarVarHandle.java
index c01f4e9..a83c3bb 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/varhandle/DesugarVarHandle.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/varhandle/DesugarVarHandle.java
@@ -10,7 +10,7 @@
 public final class DesugarVarHandle {
 
   // This only have methods found in libcore/libart/src/main/java/sun/misc/Unsafe.java for Lollipop.
-  private static class UnsafeStub {
+  public static class UnsafeStub {
 
     public long objectFieldOffset(Field f) {
       throw new RuntimeException("Stub called.");
@@ -57,6 +57,38 @@
       throw new RuntimeException("Stub called.");
     }
 
+    public void putIntVolatile(Object obj, long offset, int newValue) {
+      throw new RuntimeException("Stub called.");
+    }
+
+    public long getLongVolatile(Object obj, long offset) {
+      throw new RuntimeException("Stub called.");
+    }
+
+    public void putLongVolatile(Object obj, long offset, long newValue) {
+      throw new RuntimeException("Stub called.");
+    }
+
+    public Object getObjectVolatile(Object obj, long offset) {
+      throw new RuntimeException("Stub called.");
+    }
+
+    public void putObjectVolatile(Object obj, long offset, Object newValue) {
+      throw new RuntimeException("Stub called.");
+    }
+
+    public void putOrderedInt(Object obj, long offset, int newValue) {
+      throw new RuntimeException("Stub called.");
+    }
+
+    public void putOrderedLong(Object obj, long offset, long newValue) {
+      throw new RuntimeException("Stub called.");
+    }
+
+    public void putOrderedObject(Object obj, long offset, Object newValue) {
+      throw new RuntimeException("Stub called.");
+    }
+
     public int arrayBaseOffset(Class<?> clazz) {
       throw new RuntimeException("Stub called.");
     }
@@ -250,6 +282,109 @@
     }
   }
 
+  // getVolatile variants.
+  Object getVolatile(Object ct1) {
+    if (type == int.class) {
+      return U.getIntVolatile(ct1, offset);
+    }
+    if (type == long.class) {
+      return U.getLongVolatile(ct1, offset);
+    }
+    return U.getObjectVolatile(ct1, offset);
+  }
+
+  Object getVolatileInBox(Object ct1, Class<?> expectedBox) {
+    if (type == int.class) {
+      return boxIntIfPossible(U.getIntVolatile(ct1, offset), expectedBox);
+    }
+    if (type == long.class) {
+      return boxLongIfPossible(U.getLongVolatile(ct1, offset), expectedBox);
+    }
+    return U.getObjectVolatile(ct1, offset);
+  }
+
+  int getVolatileInt(Object ct1) {
+    if (type == int.class) {
+      return U.getIntVolatile(ct1, offset);
+    } else if (type == long.class) {
+      throw desugarWrongMethodTypeException();
+    } else {
+      return toIntIfPossible(U.getObjectVolatile(ct1, offset), true);
+    }
+  }
+
+  long getVolatileLong(Object ct1) {
+    if (type == long.class) {
+      return U.getLongVolatile(ct1, offset);
+    } else if (type == int.class) {
+      return U.getIntVolatile(ct1, offset);
+    } else {
+      return toLongIfPossible(U.getObjectVolatile(ct1, offset), true);
+    }
+  }
+
+  // setVolatile variants.
+  void setVolatile(Object ct1, Object newValue) {
+    if (type == int.class) {
+      setVolatileInt(ct1, toIntIfPossible(newValue, false));
+    } else if (type == long.class) {
+      setVolatileLong(ct1, toLongIfPossible(newValue, false));
+    } else {
+      U.putObjectVolatile(ct1, offset, newValue);
+    }
+  }
+
+  void setVolatileInt(Object ct1, int newValue) {
+    if (type == int.class) {
+      U.putIntVolatile(ct1, offset, newValue);
+    } else if (type == long.class) {
+      U.putLongVolatile(ct1, offset, newValue);
+    } else {
+      setVolatile(ct1, newValue);
+    }
+  }
+
+  void setVolatileLong(Object ct1, long newValue) {
+    if (type == long.class) {
+      U.putLongVolatile(ct1, offset, newValue);
+    } else if (type == int.class) {
+      throw desugarWrongMethodTypeException();
+    } else {
+      U.putObjectVolatile(ct1, offset, Long.valueOf(newValue));
+    }
+  }
+
+  // setRelease variants.
+  void setRelease(Object ct1, Object newValue) {
+    if (type == int.class) {
+      setReleaseInt(ct1, toIntIfPossible(newValue, false));
+    } else if (type == long.class) {
+      setReleaseLong(ct1, toLongIfPossible(newValue, false));
+    } else {
+      U.putOrderedObject(ct1, offset, newValue);
+    }
+  }
+
+  void setReleaseInt(Object ct1, int newValue) {
+    if (type == int.class) {
+      U.putOrderedInt(ct1, offset, newValue);
+    } else if (type == long.class) {
+      U.putOrderedLong(ct1, offset, newValue);
+    } else {
+      setRelease(ct1, newValue);
+    }
+  }
+
+  void setReleaseLong(Object ct1, long newValue) {
+    if (type == long.class) {
+      U.putOrderedLong(ct1, offset, newValue);
+    } else if (type == int.class) {
+      throw desugarWrongMethodTypeException();
+    } else {
+      U.putOrderedObject(ct1, offset, Long.valueOf(newValue));
+    }
+  }
+
   boolean compareAndSet(Object ct1, Object expectedValue, Object newValue) {
     if (type == int.class) {
       return U.compareAndSwapInt(
@@ -279,6 +414,41 @@
     return compareAndSet(ct1, expectedValue, newValue);
   }
 
+  // As there is no primitive for the weak behaviour in sun.misc.Unsafe this implementation
+  // behaves like compareAndSet.
+  boolean weakCompareAndSet(Object ct1, Object expectedValue, Object newValue) {
+    if (type == int.class) {
+      return U.compareAndSwapInt(
+          ct1, offset, toIntIfPossible(expectedValue, false), toIntIfPossible(newValue, false));
+    }
+    if (type == long.class) {
+      return U.compareAndSwapLong(
+          ct1, offset, toLongIfPossible(expectedValue, false), toLongIfPossible(newValue, false));
+    }
+    return U.compareAndSwapObject(ct1, offset, expectedValue, newValue);
+  }
+
+  // As there is no primitive for the weak behaviour in sun.misc.Unsafe this implementation
+  // behaves like compareAndSet.
+  boolean weakCompareAndSetInt(Object ct1, int expectedValue, int newValue) {
+    if (type == int.class) {
+      return U.compareAndSwapInt(ct1, offset, expectedValue, newValue);
+    } else if (type == long.class) {
+      return U.compareAndSwapLong(ct1, offset, expectedValue, newValue);
+    } else {
+      return compareAndSet(ct1, expectedValue, newValue);
+    }
+  }
+
+  // As there is no primitive for the weak behaviour in sun.misc.Unsafe this implementation
+  // behaves like compareAndSet.
+  boolean weakCompareAndSetLong(Object ct1, long expectedValue, long newValue) {
+    if (type == long.class) {
+      return U.compareAndSwapLong(ct1, offset, expectedValue, newValue);
+    }
+    return compareAndSet(ct1, expectedValue, newValue);
+  }
+
   // get array variants.
   Object getArray(Object ct1, int ct2) {
     if (!recv.isArray() || recv != ct1.getClass()) {
@@ -331,7 +501,59 @@
     return U.getLong(ct1, elementOffset);
   }
 
-  // get array variants.
+  // getVolatile array variants.
+  Object getVolatileArray(Object ct1, int ct2) {
+    if (!recv.isArray() || recv != ct1.getClass()) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    if (type == int.class) {
+      return U.getIntVolatile(ct1, elementOffset);
+    } else if (type == long.class) {
+      return (int) U.getLongVolatile(ct1, elementOffset);
+    } else {
+      return U.getObjectVolatile(ct1, elementOffset);
+    }
+  }
+
+  Object getVolatileArrayInBox(Object ct1, int ct2, Class<?> expectedBox) {
+    if (!recv.isArray() || recv != ct1.getClass()) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    if (type == int.class) {
+      return boxIntIfPossible(U.getIntVolatile(ct1, elementOffset), expectedBox);
+    } else if (type == long.class) {
+      return boxLongIfPossible(U.getLongVolatile(ct1, elementOffset), expectedBox);
+    } else {
+      Object value = U.getObjectVolatile(ct1, elementOffset);
+      if (value instanceof Integer && expectedBox != Integer.class) {
+        return boxIntIfPossible(((Integer) value).intValue(), expectedBox);
+      }
+      if (value instanceof Long && expectedBox != Long.class) {
+        return boxLongIfPossible(((Long) value).longValue(), expectedBox);
+      }
+      return value;
+    }
+  }
+
+  int getVolatileArrayInt(int[] ct1, int ct2) {
+    if (recv != int[].class) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    return U.getIntVolatile(ct1, elementOffset);
+  }
+
+  long getVolatileArrayLong(long[] ct1, int ct2) {
+    if (recv != long[].class) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    return U.getLongVolatile(ct1, elementOffset);
+  }
+
+  // set array variants.
   void setArray(Object ct1, int ct2, Object newValue) {
     if (!recv.isArray() || recv != ct1.getClass()) {
       throw new UnsupportedOperationException();
@@ -362,6 +584,68 @@
     U.putLong(ct1, elementOffset, newValue);
   }
 
+  // setVolatile array variants.
+  void setVolatileArray(Object ct1, int ct2, Object newValue) {
+    if (!recv.isArray() || recv != ct1.getClass()) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    if (recv == int[].class) {
+      U.putIntVolatile(ct1, elementOffset, toIntIfPossible(newValue, false));
+    } else if (recv == long[].class) {
+      U.putLongVolatile(ct1, elementOffset, toLongIfPossible(newValue, false));
+    } else {
+      U.putObjectVolatile(ct1, elementOffset, newValue);
+    }
+  }
+
+  void setVolatileArrayInt(int[] ct1, int ct2, int newValue) {
+    if (recv != int[].class) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    U.putIntVolatile(ct1, elementOffset, newValue);
+  }
+
+  void setVolatileArrayLong(long[] ct1, int ct2, long newValue) {
+    if (recv != long[].class) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    U.putLongVolatile(ct1, elementOffset, newValue);
+  }
+
+  // setRelease array variants.
+  void setReleaseArray(Object ct1, int ct2, Object newValue) {
+    if (!recv.isArray() || recv != ct1.getClass()) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    if (recv == int[].class) {
+      U.putOrderedInt(ct1, elementOffset, toIntIfPossible(newValue, false));
+    } else if (recv == long[].class) {
+      U.putOrderedLong(ct1, elementOffset, toLongIfPossible(newValue, false));
+    } else {
+      U.putOrderedObject(ct1, elementOffset, newValue);
+    }
+  }
+
+  void setReleaseArrayInt(int[] ct1, int ct2, int newValue) {
+    if (recv != int[].class) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    U.putOrderedInt(ct1, elementOffset, newValue);
+  }
+
+  void setReleaseArrayLong(long[] ct1, int ct2, long newValue) {
+    if (recv != long[].class) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    U.putOrderedLong(ct1, elementOffset, newValue);
+  }
+
   // compareAndSet array variants.
   boolean compareAndSetArray(Object ct1, int ct2, Object expetedValue, Object newValue) {
     if (!recv.isArray() || recv != ct1.getClass()) {
@@ -400,4 +684,49 @@
     long elementOffset = offset + ((long) ct2) * arrayIndexScale;
     return U.compareAndSwapLong(ct1, elementOffset, expetedValue, newValue);
   }
+
+  // weakCompareAndSet array variants.
+  // As there is no primitive for the weak behaviour in sun.misc.Unsafe this implementation
+  // behaves like compareAndSet.
+  boolean weakCompareAndSetArray(Object ct1, int ct2, Object expetedValue, Object newValue) {
+    if (!recv.isArray() || recv != ct1.getClass()) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    if (recv == int[].class) {
+      return U.compareAndSwapInt(
+          ct1,
+          elementOffset,
+          toIntIfPossible(expetedValue, false),
+          toIntIfPossible(newValue, false));
+    } else if (recv == long[].class) {
+      return U.compareAndSwapLong(
+          ct1,
+          elementOffset,
+          toLongIfPossible(expetedValue, false),
+          toLongIfPossible(newValue, false));
+    } else {
+      return U.compareAndSwapObject(ct1, elementOffset, expetedValue, newValue);
+    }
+  }
+
+  // As there is no primitive for the weak behaviour in sun.misc.Unsafe this implementation
+  // behaves like compareAndSet.
+  boolean weakCompareAndSetArrayInt(int[] ct1, int ct2, int expetedValue, int newValue) {
+    if (recv != int[].class) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    return U.compareAndSwapInt(ct1, elementOffset, expetedValue, newValue);
+  }
+
+  // As there is no primitive for the weak behaviour in sun.misc.Unsafe this implementation
+  // behaves like compareAndSet.
+  boolean weakCompareAndSetArrayLong(long[] ct1, int ct2, long expetedValue, long newValue) {
+    if (recv != long[].class) {
+      throw new UnsupportedOperationException();
+    }
+    long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+    return U.compareAndSwapLong(ct1, elementOffset, expetedValue, newValue);
+  }
 }
diff --git a/src/test/java/com/android/tools/r8/ir/desugar/varhandle/GenerateVarHandleMethods.java b/src/test/java/com/android/tools/r8/ir/desugar/varhandle/GenerateVarHandleMethods.java
index 0c65df4..1823867 100644
--- a/src/test/java/com/android/tools/r8/ir/desugar/varhandle/GenerateVarHandleMethods.java
+++ b/src/test/java/com/android/tools/r8/ir/desugar/varhandle/GenerateVarHandleMethods.java
@@ -21,6 +21,7 @@
 import com.android.tools.r8.graph.DexMethod;
 import com.android.tools.r8.graph.DexProto;
 import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.DescriptorUtils;
 import com.android.tools.r8.utils.FileUtils;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
@@ -42,7 +43,7 @@
 public class GenerateVarHandleMethods extends MethodGenerationBase {
 
   private final DexType GENERATED_TYPE =
-      factory.createType("Lcom/android/tools/r8/ir/desugar/varhandle/VarHandleDesugaringMethods;");
+      factory.createType(DescriptorUtils.javaClassToDescriptor(VarHandleDesugaringMethods.class));
   private final List<Class<?>> METHOD_TEMPLATE_CLASSES =
       ImmutableList.of(DesugarMethodHandlesLookup.class, DesugarVarHandle.class);
 
@@ -87,9 +88,7 @@
   protected DexEncodedField getField(DexEncodedField field) {
     if (field.getType().getTypeName().endsWith("$UnsafeStub")) {
       return DexEncodedField.builder(field)
-          .setField(
-              factory.createField(
-                  field.getHolderType(), factory.createType("Lsun/misc/Unsafe;"), field.getName()))
+          .setField(factory.createField(field.getHolderType(), factory.unsafeType, field.getName()))
           .disableAndroidApiLevelCheck()
           .build();
     }
@@ -181,13 +180,12 @@
         new InstructionTypeMapper(
             ImmutableMap.of(
                 factory.createType(
-                    "L" + DesugarMethodHandlesLookup.class.getTypeName().replace('.', '/') + ";"),
+                    DescriptorUtils.javaClassToDescriptor(DesugarMethodHandlesLookup.class)),
                 factory.lookupType,
-                factory.createType(
-                    "L" + DesugarVarHandle.class.getTypeName().replace('.', '/') + ";"),
+                factory.createType(DescriptorUtils.javaClassToDescriptor(DesugarVarHandle.class)),
                 factory.varHandleType,
                 factory.createType(
-                    "L" + DesugarVarHandle.class.getTypeName().replace('.', '/') + "$UnsafeStub;"),
+                    DescriptorUtils.javaClassToDescriptor(DesugarVarHandle.UnsafeStub.class)),
                 factory.unsafeType),
             GenerateVarHandleMethods::mapMethodName);
     code.setInstructions(
@@ -200,15 +198,22 @@
   private DexEncodedMethod methodWithName(DexEncodedMethod method, String name) {
     DexType holder = method.getHolderType();
     DexType varHandle = factory.varHandleType;
+    DexType methodHandlesLookup = factory.lookupType;
     DexType desugarVarHandleStub =
-        factory.createType("L" + DesugarVarHandle.class.getTypeName().replace('.', '/') + ";");
+        factory.createType(DescriptorUtils.javaClassToDescriptor(DesugarVarHandle.class));
+    DexType desugarMethodHandlesLookupStub =
+        factory.createType(DescriptorUtils.javaClassToDescriptor(DesugarMethodHandlesLookup.class));
     // Map methods to be on the final DesugarVarHandle class.
     if (holder == desugarVarHandleStub) {
       holder = varHandle;
+    } else if (holder == desugarMethodHandlesLookupStub) {
+      holder = methodHandlesLookup;
     }
     DexProto proto = method.getProto();
     if (proto.getReturnType() == desugarVarHandleStub) {
       proto = factory.createProto(varHandle, proto.parameters);
+    } else if (proto.getReturnType() == desugarMethodHandlesLookupStub) {
+      proto = factory.createProto(methodHandlesLookup, proto.parameters);
     }
     return DexEncodedMethod.syntheticBuilder(method)
         .setMethod(factory.createMethod(holder, proto, factory.createString(name)))
@@ -224,7 +229,15 @@
   private static String mapMethodName(String name) {
     Set<String> postfixes =
         ImmutableSet.of("InBox", "Int", "Long", "Array", "ArrayInBox", "ArrayInt", "ArrayLong");
-    for (String prefix : ImmutableList.of("get", "set", "compareAndSet")) {
+    for (String prefix :
+        ImmutableList.of(
+            "get",
+            "set",
+            "compareAndSet",
+            "weakCompareAndSet",
+            "getVolatile",
+            "setVolatile",
+            "setRelease")) {
       if (name.startsWith(prefix)) {
         String postfix = name.substring(prefix.length());
         if (postfixes.contains(postfix)) {
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsTest.java
new file mode 100644
index 0000000..e228204
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsTest.java
@@ -0,0 +1,64 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.mappingcompose;
+
+import static com.android.tools.r8.mappingcompose.ComposeTestHelpers.doubleToSingleQuote;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.MappingComposer;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ComposeInlineOfPositionsTest extends TestBase {
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public ComposeInlineOfPositionsTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
+
+  private static final String mappingFoo =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "com.foo -> a:",
+          "    1:1:void m1():10 -> x",
+          "    2:2:void m2(int):20 -> x",
+          "    3:4:void y():30:31 -> y");
+  private static final String mappingBar =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "a -> b:",
+          "    3:3:void x():1:1 -> z",
+          "    3:3:void y():3 -> z",
+          "    4:4:void x(int):2:2 -> z",
+          "    4:4:void y():4 -> z");
+  private static final String mappingResult =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "com.foo -> b:",
+          "    3:3:void m1():10 -> z",
+          "    3:3:void y():30:30 -> z",
+          "    4:4:void m2(int):20 -> z",
+          "    4:4:void y():31:31 -> z");
+
+  @Test
+  public void testCompose() throws Exception {
+    ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo);
+    ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar);
+    String composed = MappingComposer.compose(mappingForFoo, mappingForBar);
+    assertEquals(mappingResult, doubleToSingleQuote(composed));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsThatViolateNewRangeTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsThatViolateNewRangeTest.java
new file mode 100644
index 0000000..a732f72
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlineOfPositionsThatViolateNewRangeTest.java
@@ -0,0 +1,73 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.mappingcompose;
+
+import static com.android.tools.r8.mappingcompose.ComposeTestHelpers.doubleToSingleQuote;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.MappingComposer;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ComposeInlineOfPositionsThatViolateNewRangeTest extends TestBase {
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public ComposeInlineOfPositionsThatViolateNewRangeTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
+
+  private static final String mappingFoo =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "com.foo -> a:",
+          "    1:1:void m1():10 -> x",
+          "    2:2:void m2(int):20 -> x",
+          "    3:4:void y():30:31 -> y");
+  private static final String mappingBar =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "a -> b:",
+          "    3:3:void x():1:1 -> z",
+          "    3:3:void y():3 -> z",
+          "    4:4:void x(int):2:2 -> z",
+          "    4:4:void y():4 -> z");
+  private static final String mappingBaz =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "b -> c:",
+          "    10:11:void z():3:4 -> w",
+          "    10:11:void new_synthetic_method():0 -> w");
+  private static final String mappingResult =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "com.foo -> c:",
+          "    10:10:void m1():10 -> w",
+          "    10:10:void y():30:30 -> w",
+          "    10:10:void new_synthetic_method():0:0 -> w",
+          "    11:11:void m2(int):20 -> w",
+          "    11:11:void y():31:31 -> w",
+          "    11:11:void new_synthetic_method():0:0 -> w");
+
+  @Test
+  public void testCompose() throws Exception {
+    ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo);
+    ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar);
+    ClassNameMapper mappingForBaz = ClassNameMapper.mapperFromString(mappingBaz);
+    String composed = MappingComposer.compose(mappingForFoo, mappingForBar, mappingForBaz);
+    assertEquals(mappingResult, doubleToSingleQuote(composed));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlinePartialChangeTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlinePartialChangeTest.java
new file mode 100644
index 0000000..98aeb52
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeInlinePartialChangeTest.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.mappingcompose;
+
+import static com.android.tools.r8.mappingcompose.ComposeTestHelpers.doubleToSingleQuote;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.MappingComposer;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ComposeInlinePartialChangeTest extends TestBase {
+
+  @Parameter() public TestParameters parameters;
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  private static final String mappingFoo =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "com.foo -> a:",
+          "    1:1:void caller():39:39 -> x",
+          "    2:2:void inlinee1():42:42 -> x",
+          "    2:2:void caller():40 -> x",
+          "    3:3:void inlinee1():43:43 -> x",
+          "    3:3:void caller():41 -> x",
+          "    4:4:void caller():42 -> x");
+  private static final String mappingBar =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "a -> b:",
+          "    9:12:void x():1:4 -> y");
+  private static final String mappingResult =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "com.foo -> b:",
+          "    9:9:void caller():39:39 -> y",
+          "    10:10:void inlinee1():42:42 -> y",
+          "    10:10:void caller():40 -> y",
+          "    11:11:void inlinee1():43:43 -> y",
+          "    11:11:void caller():41 -> y",
+          "    12:12:void caller():42 -> y");
+
+  @Test
+  public void testCompose() throws Exception {
+    ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo);
+    ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar);
+    String composed = MappingComposer.compose(mappingForFoo, mappingForBar);
+    assertEquals(mappingResult, doubleToSingleQuote(composed));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposeOriginalViolatesNewRangeTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOriginalViolatesNewRangeTest.java
new file mode 100644
index 0000000..fe94d29
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposeOriginalViolatesNewRangeTest.java
@@ -0,0 +1,58 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.mappingcompose;
+
+import static com.android.tools.r8.mappingcompose.ComposeTestHelpers.doubleToSingleQuote;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.MappingComposer;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ComposeOriginalViolatesNewRangeTest extends TestBase {
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public ComposeOriginalViolatesNewRangeTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
+
+  private static final String mappingFoo =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "com.foo -> a:",
+          "    1:1:void m1():10:10 -> x",
+          "    2:2:void m1():20:20 -> x");
+  private static final String mappingBar =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "a -> b:",
+          "    3:4:void x():1:2 -> z");
+  private static final String mappingResult =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "com.foo -> b:",
+          "    3:3:void m1():10:10 -> z",
+          "    4:4:void m1():20:20 -> z");
+
+  @Test
+  public void testCompose() throws Exception {
+    ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo);
+    ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar);
+    String composed = MappingComposer.compose(mappingForFoo, mappingForBar);
+    assertEquals(mappingResult, doubleToSingleQuote(composed));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposePreambleSyntheticTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposePreambleSyntheticTest.java
new file mode 100644
index 0000000..71c344d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposePreambleSyntheticTest.java
@@ -0,0 +1,62 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.mappingcompose;
+
+import static com.android.tools.r8.mappingcompose.ComposeTestHelpers.doubleToSingleQuote;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.MappingComposer;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ComposePreambleSyntheticTest extends TestBase {
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public ComposePreambleSyntheticTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
+
+  private static final String mappingFoo =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "com.foo -> a:",
+          "    1:1:void lambda$0(boolean):355:355 ->" + " lambda$0");
+  private static final String mappingBar =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "a -> b:",
+          "    1:2:void lambda$0(boolean):0:1 ->" + " lambda$0$com-r8-Base",
+          "    1:2:void" + " lambda$0$com-r8-Base(boolean):0" + " -> lambda$0$com-r8-Base",
+          "    # {'id':'com.android.tools.r8.synthesized'}");
+  private static final String mappingResult =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "com.foo -> b:",
+          "    1:1:void lambda$0(boolean):0:0 -> lambda$0$com-r8-Base",
+          "    1:1:void lambda$0$com-r8-Base(boolean):0:0 -> lambda$0$com-r8-Base",
+          "    2:2:void lambda$0(boolean):355:355 -> lambda$0$com-r8-Base",
+          "    2:2:void lambda$0$com-r8-Base(boolean):0:0 -> lambda$0$com-r8-Base",
+          "    # {'id':'com.android.tools.r8.synthesized'}");
+
+  @Test
+  public void testCompose() throws Exception {
+    ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo);
+    ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar);
+    String composed = MappingComposer.compose(mappingForFoo, mappingForBar);
+    assertEquals(mappingResult, doubleToSingleQuote(composed));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/mappingcompose/ComposePreambleTest.java b/src/test/java/com/android/tools/r8/mappingcompose/ComposePreambleTest.java
new file mode 100644
index 0000000..57b70a0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/mappingcompose/ComposePreambleTest.java
@@ -0,0 +1,60 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.mappingcompose;
+
+import static com.android.tools.r8.mappingcompose.ComposeTestHelpers.doubleToSingleQuote;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.naming.MappingComposer;
+import com.android.tools.r8.utils.StringUtils;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ComposePreambleTest extends TestBase {
+
+  @Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public ComposePreambleTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
+
+  private static final String mappingFoo =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "com.foo -> a:",
+          "    1:2:int f1():41:42 -> g1",
+          "    112:112:void f2():112:112 -> g2");
+  private static final String mappingBar =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "a -> b:",
+          "    1:3:int g1():0:2 -> h1",
+          "    0:65535:void g2():112:112 -> h2");
+  private static final String mappingResult =
+      StringUtils.unixLines(
+          "# {'id':'com.android.tools.r8.mapping','version':'2.2'}",
+          "com.foo -> b:",
+          "    1:1:int f1():0:0 -> h1",
+          "    2:3:int f1():41:42 -> h1",
+          "    0:65535:void f2():112:112 -> h2");
+
+  @Test
+  public void testCompose() throws Exception {
+    ClassNameMapper mappingForFoo = ClassNameMapper.mapperFromString(mappingFoo);
+    ClassNameMapper mappingForBar = ClassNameMapper.mapperFromString(mappingBar);
+    String composed = MappingComposer.compose(mappingForFoo, mappingForBar);
+    assertEquals(mappingResult, doubleToSingleQuote(composed));
+  }
+}
diff --git a/src/test/java/com/android/tools/r8/retrace/RetraceStackTraceFunctionalCompositionTest.java b/src/test/java/com/android/tools/r8/retrace/RetraceStackTraceFunctionalCompositionTest.java
index 7513419..367e1b6 100644
--- a/src/test/java/com/android/tools/r8/retrace/RetraceStackTraceFunctionalCompositionTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/RetraceStackTraceFunctionalCompositionTest.java
@@ -36,7 +36,6 @@
 import java.util.Map;
 import java.util.Map.Entry;
 import java.util.function.Supplier;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.junit.runners.Parameterized;
@@ -157,7 +156,6 @@
     return rewrittenR8Jar;
   }
 
-  @Ignore("b/255292908")
   @Test
   public void testR8RetraceAndComposition() throws Exception {
     Path rewrittenR8Jar = getRewrittenR8Jar();
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/ConditionalKeepRulePrintingTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/ConditionalKeepRulePrintingTest.java
new file mode 100644
index 0000000..9245a4d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/ConditionalKeepRulePrintingTest.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2023, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+package com.android.tools.r8.shaking.ifrule;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class ConditionalKeepRulePrintingTest extends TestBase {
+
+  @Parameterized.Parameters(name = "{0}")
+  public static TestParametersCollection data() {
+    return getTestParameters().withNoneRuntime().build();
+  }
+
+  public ConditionalKeepRulePrintingTest(TestParameters parameters) {
+    parameters.assertNoneRuntime();
+  }
+
+  @Test
+  public void test() throws Exception {
+    testForR8(Backend.CF)
+        .addInnerClasses(ConditionalKeepRulePrintingTest.class)
+        .addKeepClassRules(TestClass.class)
+        .addKeepRules(
+            "-if class "
+                + typeName(TestClass.class)
+                + " -keep class "
+                + typeName(TestClass.class)
+                + " { *** main(...); }")
+        .compile()
+        .apply(
+            r -> {
+              assertThat(r.getProguardConfiguration().toString(), containsString("*** main(...);"));
+            });
+  }
+
+  static class TestClass {
+
+    public static void main(String[] args) {
+      System.out.println("Hello, world");
+    }
+  }
+}
diff --git a/tools/r8_release.py b/tools/r8_release.py
index 78fd031..c799d90 100755
--- a/tools/r8_release.py
+++ b/tools/r8_release.py
@@ -562,30 +562,40 @@
     configuration_version = args.desugar_library[1]
 
     # TODO(b/237636871): Cleanup and generalize.
-    if (not (library_version.startswith('1.1') or library_version.startswith('1.2'))):
+    if (not (library_version.startswith('1.1')
+        or library_version.startswith('1.2')
+        or library_version.startswith('2.0'))):
       print("Release script does not support desugared library version %s"
         % library_version)
       sys.exit(1)
 
-    postfix = "" if library_version.startswith('1.1') else '_jdk11_legacy'
-    library_archive = DESUGAR_JDK_LIBS + postfix + '.zip'
-    library_jar = DESUGAR_JDK_LIBS + postfix + '.jar'
-
-    configuration_archive = DESUGAR_JDK_LIBS_CONFIGURATION + postfix + '.zip'
+    postfixes = ['']
+    if library_version.startswith('1.2'):
+      postfixes = ['_legacy']
+    if library_version.startswith('2.0'):
+      postfixes = ['_minimal', '', '_nio']
 
     with utils.TempDir() as temp:
       with utils.ChangedWorkingDirectory(temp):
-        library_gfile = ('/bigstore/r8-releases/raw/%s/%s/%s'
-              % (DESUGAR_JDK_LIBS, library_version, library_archive))
-        configuration_gfile = ('/bigstore/r8-releases/raw/main/%s/%s'
-              % (configuration_version, configuration_archive))
+        artifacts = []
+        for postfix in postfixes:
+          group_postfix = ('' if postfix == '_legacy' else postfix)
+          archive_postfix = (postfix if library_version.startswith('1.1') else '_jdk11' + postfix)
+          library_jar = DESUGAR_JDK_LIBS + postfix + '.jar'
+          library_archive = DESUGAR_JDK_LIBS + archive_postfix + '.zip'
+          configuration_archive = DESUGAR_JDK_LIBS_CONFIGURATION + archive_postfix + '.zip'
+          library_gfile = ('/bigstore/r8-releases/raw/%s/%s/%s'
+                % (DESUGAR_JDK_LIBS + group_postfix, library_version, library_archive))
+          configuration_gfile = ('/bigstore/r8-releases/raw/main/%s/%s'
+                % (configuration_version, configuration_archive))
 
-        download_gfile(library_gfile, library_archive)
-        download_gfile(configuration_gfile, configuration_archive)
-        check_configuration(configuration_archive)
+          download_gfile(library_gfile, library_archive)
+          download_gfile(configuration_gfile, configuration_archive)
+          check_configuration(configuration_archive, group_postfix)
+          artifacts.append(library_gfile)
+          artifacts.append(configuration_gfile)
 
-        release_id = gmaven_publisher_stage(
-            args, [library_gfile, configuration_gfile])
+        release_id = gmaven_publisher_stage(args, artifacts)
 
         print("Staged Release ID " + release_id + ".\n")
         library_artifact_id = \
@@ -610,11 +620,11 @@
   return make_release
 
 
-def check_configuration(configuration_archive):
+def check_configuration(configuration_archive, postfix):
   zip = zipfile.ZipFile(configuration_archive)
   zip.extractall()
   dirs = os.listdir(
-    os.path.join('com', 'android', 'tools', DESUGAR_JDK_LIBS_CONFIGURATION))
+    os.path.join('com', 'android', 'tools', DESUGAR_JDK_LIBS_CONFIGURATION + postfix))
   if len(dirs) != 1:
     print('Unexpected archive content, %s' + dirs)
     sys.exit(1)
@@ -624,9 +634,9 @@
     'com',
     'android',
     'tools',
-    DESUGAR_JDK_LIBS_CONFIGURATION,
+    DESUGAR_JDK_LIBS_CONFIGURATION + postfix,
     version,
-    '%s-%s.pom' % (DESUGAR_JDK_LIBS_CONFIGURATION, version))
+    '%s-%s.pom' % (DESUGAR_JDK_LIBS_CONFIGURATION + postfix, version))
   version_from_pom = extract_version_from_pom(pom_file)
   if version != version_from_pom:
     print('Version mismatch, %s != %s' % (version, version_from_pom))