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))