VarHandle desugar: Add support for array element var handles
Support is limited to single dimension arrays of int, long and reference
types.
Bug: b/247076137
Change-Id: Ic6485ca4bf11610efb24052793594526688f355e
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
index df1ba99..8bd0077 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/CfInstructionDesugaringEventConsumer.java
@@ -155,7 +155,9 @@
@Override
public void acceptVarHandleDesugaringClass(DexProgramClass clazz) {
- methodProcessor.scheduleDesugaredMethodsForProcessing(clazz.programMethods());
+ clazz
+ .programMethods()
+ .forEach(method -> methodProcessor.scheduleMethodForProcessing(method, this));
}
@Override
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 b83c526..6aaf59d 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
@@ -258,24 +258,36 @@
&& method.getArity() == 0
&& invoke.isInvokeStatic()) {
return computeMethodHandlesLookup(factory);
+ } else if (method.getName().equals(factory.createString("arrayElementVarHandle"))
+ && method.getReturnType() == factory.varHandleType
+ && method.getArity() == 1
+ && method.getParameter(0) == factory.classType
+ && invoke.isInvokeStatic()) {
+ return computeMethodHandlesArrayElementVarHandle(factory);
} else {
return DesugarDescription.nothing();
}
}
if (method.getHolderType() == factory.varHandleType) {
+ if (!invoke.isInvokeVirtual()) {
+ // Right now only <init> should be hit from MethodHandles.Lookup desugaring creating
+ // a VarHandle instance.
+ assert invoke.isInvokeSpecial();
+ return DesugarDescription.nothing();
+ }
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)) {
- assert arity == 3;
+ assert arity == 3 || arity == 4;
return computeDesugarSignaturePolymorphicMethod(invoke, arity - 2);
} else if (name.equals(factory.getString)) {
- assert arity == 1;
+ assert arity == 1 || arity == 2;
return computeDesugarSignaturePolymorphicMethod(invoke, arity);
} else if (name.equals(factory.setString)) {
- assert arity == 2;
+ assert arity == 2 || arity == 3;
return computeDesugarSignaturePolymorphicMethod(invoke, arity - 1);
} else {
// TODO(b/247076137): Insert runtime exception - unsupported VarHandle operation.
@@ -308,6 +320,29 @@
.build();
}
+ public DesugarDescription computeMethodHandlesArrayElementVarHandle(DexItemFactory factory) {
+ return DesugarDescription.builder()
+ .setDesugarRewrite(
+ (freshLocalProvider,
+ localStackAllocator,
+ 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)))
+ .build();
+ }
+
public DesugarDescription computeDesugarSignaturePolymorphicMethod(
CfInvoke invoke, int coordinates) {
return DesugarDescription.builder()
@@ -338,24 +373,38 @@
CfInvoke invoke, int coordinates, FreshLocalProvider freshLocalProvider) {
assert invoke.isInvokeVirtual();
// TODO(b/247076137): Support two coordinates (array element VarHandle).
- assert coordinates == 1 && invoke.getMethod().getProto().getArity() >= coordinates;
+ assert (coordinates == 1 || coordinates == 2)
+ && invoke.getMethod().getProto().getArity() >= coordinates;
// Only support zero, one and two arguments after coordinates.
int nonCoordinateArguments = invoke.getMethod().getProto().getArity() - coordinates;
assert nonCoordinateArguments <= 2;
DexProto proto = invoke.getMethod().getProto();
DexType ct1Type = invoke.getMethod().getProto().getParameter(0);
- if (!ct1Type.isClassType()) {
+ if (!ct1Type.isClassType() && !ct1Type.isArrayType()) {
return null;
}
+ DexType ct1ElementType = null;
+ if (ct1Type.isArrayType()) {
+ ct1ElementType = ct1Type.toDimensionMinusOneType(factory);
+ if (ct1ElementType != factory.intType
+ && ct1ElementType != factory.longType
+ && !ct1ElementType.isReferenceType()) {
+ return null;
+ }
+ DexType ct2Type = invoke.getMethod().getProto().getParameter(1);
+ if (ct2Type != factory.intType) {
+ return null;
+ }
+ }
// Convert the arguments by boxing except for primitive int and long.
ImmutableList.Builder<CfInstruction> builder = ImmutableList.builder();
List<DexType> newParameters = new ArrayList<>(proto.parameters.size());
- newParameters.add(factory.objectType);
+ DexType argumentType = null;
+ boolean hasWideArgument = false;
if (nonCoordinateArguments > 0) {
- DexType argumentType = objectOrPrimitiveParameterType(proto.parameters.get(coordinates));
- boolean hasWideArgument = false;
+ argumentType = objectOrPrimitiveParameterType(proto.parameters.get(coordinates));
for (int i = coordinates; i < proto.parameters.size(); i++) {
hasWideArgument = hasWideArgument || proto.parameters.get(i).isWideType();
DexType type = objectOrPrimitiveParameterType(proto.parameters.get(i));
@@ -364,51 +413,78 @@
}
}
assert isPrimitiveThatIsNotBoxed(argumentType) || argumentType == factory.objectType;
- // Ensure all arguments are boxed.
- for (int i = coordinates; i < proto.parameters.size(); i++) {
- if (argumentType.isPrimitiveType()) {
- newParameters.add(argumentType);
- } else {
- boolean lastArgument = i == proto.parameters.size() - 1;
- // Pass all boxed objects as Object.
- newParameters.add(factory.objectType);
- if (!proto.parameters.get(i).isPrimitiveType()) {
- continue;
- }
- int local = -1;
- // For boxing of the second to last argument (we only have one or two) bring it to TOS.
- if (!lastArgument) {
- if (hasWideArgument) {
- local = freshLocalProvider.getFreshLocal(2);
- builder.add(new CfStore(ValueType.fromDexType(proto.parameters.get(i + 1)), local));
- } else {
- builder.add(new CfStackInstruction(Opcode.Swap));
- }
- }
- builder.add(
- new CfInvoke(
- Opcodes.INVOKESTATIC,
- factory.getBoxPrimitiveMethod(proto.parameters.get(i)),
- false));
- // When boxing of the second to last argument (we only have one or two) bring last
- // argument back to TOS.
- if (!lastArgument) {
- if (hasWideArgument) {
- assert local != -1;
- builder.add(new CfLoad(ValueType.fromDexType(proto.parameters.get(i + 1)), local));
- } else {
- builder.add(new CfStackInstruction(Opcode.Swap));
- }
- }
- }
- }
}
- assert newParameters.size() == proto.parameters.size();
DexString name = invoke.getMethod().getName();
DexType returnType =
factory.polymorphicMethods.varHandleCompareAndSetMethodNames.contains(name)
? proto.returnType
: objectOrPrimitiveReturnType(proto.returnType);
+
+ if (coordinates == 1) {
+ newParameters.add(factory.objectType);
+ } else {
+ assert coordinates == 2;
+ // For array VarHandle only use the method with primitive arguments if all relevant parts of
+ // the signature has the same primitive type.
+ assert ct1ElementType != null;
+ boolean usePrimitiveArray =
+ ct1ElementType.isPrimitiveType()
+ && (argumentType == null || argumentType == ct1ElementType)
+ && (factory.polymorphicMethods.varHandleCompareAndSetMethodNames.contains(name)
+ || returnType.isVoidType()
+ || returnType == ct1ElementType);
+ newParameters.add(usePrimitiveArray ? ct1Type : factory.objectType);
+ newParameters.add(factory.intType);
+ if (!usePrimitiveArray) {
+ if (argumentType != null) {
+ argumentType = factory.objectType;
+ }
+ if (!factory.polymorphicMethods.varHandleCompareAndSetMethodNames.contains(name)
+ && !returnType.isVoidType()) {
+ returnType = factory.objectType;
+ }
+ }
+ }
+
+ // Ensure all arguments are boxed if required.
+ for (int i = coordinates; i < proto.parameters.size(); i++) {
+ if (argumentType.isPrimitiveType()) {
+ newParameters.add(argumentType);
+ } else {
+ boolean lastArgument = i == proto.parameters.size() - 1;
+ // Pass all boxed objects as Object.
+ newParameters.add(factory.objectType);
+ if (!proto.parameters.get(i).isPrimitiveType()) {
+ continue;
+ }
+ int local = -1;
+ // For boxing of the second to last argument (we only have one or two) bring it to TOS.
+ if (!lastArgument) {
+ if (hasWideArgument) {
+ local = freshLocalProvider.getFreshLocal(2);
+ builder.add(new CfStore(ValueType.fromDexType(proto.parameters.get(i + 1)), local));
+ } else {
+ builder.add(new CfStackInstruction(Opcode.Swap));
+ }
+ }
+ builder.add(
+ new CfInvoke(
+ Opcodes.INVOKESTATIC,
+ factory.getBoxPrimitiveMethod(proto.parameters.get(i)),
+ false));
+ // When boxing of the second to last argument (we only have one or two) bring last
+ // argument back to TOS.
+ if (!lastArgument) {
+ if (hasWideArgument) {
+ assert local != -1;
+ builder.add(new CfLoad(ValueType.fromDexType(proto.parameters.get(i + 1)), local));
+ } else {
+ builder.add(new CfStackInstruction(Opcode.Swap));
+ }
+ }
+ }
+ }
+ assert newParameters.size() == proto.parameters.size();
if (proto.returnType != returnType) {
if (proto.returnType.isPrimitiveType()) {
builder.add(new CfConstClass(factory.getBoxedForPrimitiveType(proto.returnType)));
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 9f1ba61..c2673ba 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
@@ -8,6 +8,7 @@
package com.android.tools.r8.ir.desugar.varhandle;
+import com.android.tools.r8.cf.code.CfArithmeticBinop;
import com.android.tools.r8.cf.code.CfCheckCast;
import com.android.tools.r8.cf.code.CfConstClass;
import com.android.tools.r8.cf.code.CfConstNull;
@@ -54,6 +55,7 @@
factory.createSynthesizedType("Ljava/lang/ClassCastException;");
factory.createSynthesizedType("Ljava/lang/Double;");
factory.createSynthesizedType("Ljava/lang/Float;");
+ factory.createSynthesizedType("Ljava/lang/IllegalArgumentException;");
factory.createSynthesizedType("Ljava/lang/Integer;");
factory.createSynthesizedType("Ljava/lang/Long;");
factory.createSynthesizedType("Ljava/lang/RuntimeException;");
@@ -101,23 +103,122 @@
builder.getType(), factory.longType, factory.createString("offset")))
.setAccessFlags(FieldAccessFlags.createPublicFinalSynthetic())
.disableAndroidApiLevelCheck()
+ .build(),
+ DexEncodedField.syntheticBuilder()
+ .setField(
+ factory.createField(
+ builder.getType(),
+ factory.longType,
+ factory.createString("arrayIndexScale")))
+ .setAccessFlags(FieldAccessFlags.createPublicFinalSynthetic())
+ .disableAndroidApiLevelCheck()
.build()));
DexMethod toIntIfPossible =
factory.createMethod(
builder.getType(),
factory.createProto(factory.intType, factory.objectType, factory.booleanType),
factory.createString("toIntIfPossible"));
- DexMethod get =
- factory.createMethod(
- builder.getType(),
- factory.createProto(factory.objectType, factory.objectType),
- factory.createString("get"));
DexMethod compareAndSet =
factory.createMethod(
builder.getType(),
factory.createProto(
factory.booleanType, factory.objectType, factory.objectType, factory.objectType),
factory.createString("compareAndSet"));
+ DexMethod getArrayInBox =
+ factory.createMethod(
+ builder.getType(),
+ factory.createProto(
+ factory.objectType,
+ factory.objectType,
+ 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(),
+ factory.createProto(
+ factory.objectType,
+ factory.intType,
+ factory.createType(factory.createString("Ljava/lang/Class;"))),
+ factory.createString("boxIntIfPossible"));
+ DexMethod desugarWrongMethodTypeException =
+ factory.createMethod(
+ builder.getType(),
+ factory.createProto(
+ factory.createType(factory.createString("Ljava/lang/RuntimeException;"))),
+ factory.createString("desugarWrongMethodTypeException"));
+ DexMethod setArrayLong =
+ factory.createMethod(
+ builder.getType(),
+ factory.createProto(
+ factory.voidType,
+ factory.createType(factory.createString("[J")),
+ factory.intType,
+ factory.longType),
+ factory.createString("set"));
+ DexMethod getInt =
+ factory.createMethod(
+ builder.getType(),
+ factory.createProto(factory.intType, factory.objectType),
+ factory.createString("get"));
+ DexMethod getArrayLong =
+ factory.createMethod(
+ builder.getType(),
+ factory.createProto(
+ factory.longType, factory.createType(factory.createString("[J")), factory.intType),
+ factory.createString("get"));
+ DexMethod getLong =
+ factory.createMethod(
+ builder.getType(),
+ factory.createProto(factory.longType, factory.objectType),
+ factory.createString("get"));
+ DexMethod compareAndSetArrayLong =
+ factory.createMethod(
+ builder.getType(),
+ factory.createProto(
+ factory.booleanType,
+ factory.createType(factory.createString("[J")),
+ factory.intType,
+ factory.longType,
+ factory.longType),
+ factory.createString("compareAndSet"));
+ DexMethod getInBox =
+ factory.createMethod(
+ builder.getType(),
+ factory.createProto(
+ factory.objectType,
+ factory.objectType,
+ factory.createType(factory.createString("Ljava/lang/Class;"))),
+ factory.createString("get"));
+ DexMethod get =
+ factory.createMethod(
+ builder.getType(),
+ factory.createProto(factory.objectType, factory.objectType),
+ factory.createString("get"));
+ 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 constructor_1 =
factory.createMethod(
builder.getType(),
@@ -138,11 +239,19 @@
factory.createType(factory.createString("Ljava/lang/String;")),
factory.createType(factory.createString("Ljava/lang/Class;"))),
factory.createString("<init>"));
- DexMethod setLong =
+ DexMethod arrayRequiringNativeSupport =
factory.createMethod(
builder.getType(),
- factory.createProto(factory.voidType, factory.objectType, factory.longType),
- factory.createString("set"));
+ 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 compareAndSetLong =
factory.createMethod(
builder.getType(),
@@ -159,35 +268,38 @@
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 =
factory.createMethod(
builder.getType(),
factory.createProto(
factory.booleanType, factory.objectType, factory.intType, factory.intType),
factory.createString("compareAndSet"));
- DexMethod desugarWrongMethodTypeException =
+ DexMethod compareAndSetArray =
factory.createMethod(
builder.getType(),
factory.createProto(
- factory.createType(factory.createString("Ljava/lang/RuntimeException;"))),
- factory.createString("desugarWrongMethodTypeException"));
- DexMethod getInt =
- factory.createMethod(
- builder.getType(),
- factory.createProto(factory.intType, factory.objectType),
- factory.createString("get"));
- DexMethod getLong =
- factory.createMethod(
- builder.getType(),
- factory.createProto(factory.longType, factory.objectType),
- factory.createString("get"));
- DexMethod getInBox =
- factory.createMethod(
- builder.getType(),
- factory.createProto(
+ factory.booleanType,
factory.objectType,
+ factory.intType,
factory.objectType,
- factory.createType(factory.createString("Ljava/lang/Class;"))),
+ factory.objectType),
+ factory.createString("compareAndSet"));
+ DexMethod getArray =
+ factory.createMethod(
+ builder.getType(),
+ factory.createProto(factory.objectType, factory.objectType, factory.intType),
factory.createString("get"));
builder.setDirectMethods(
ImmutableList.of(
@@ -218,6 +330,104 @@
.disableAndroidApiLevelCheck()
.build(),
DexEncodedMethod.syntheticBuilder()
+ .setMethod(compareAndSet)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+ .setCode(DesugarVarHandle_compareAndSet(factory, compareAndSet))
+ .disableAndroidApiLevelCheck()
+ .build(),
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(getArrayInBox)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+ .setCode(DesugarVarHandle_getArrayInBox(factory, getArrayInBox))
+ .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(
+ Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+ .setCode(DesugarVarHandle_boxIntIfPossible(factory, boxIntIfPossible))
+ .disableAndroidApiLevelCheck()
+ .build(),
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(desugarWrongMethodTypeException)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+ .setCode(
+ DesugarVarHandle_desugarWrongMethodTypeException(
+ factory, desugarWrongMethodTypeException))
+ .disableAndroidApiLevelCheck()
+ .build(),
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(setArrayLong)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+ .setCode(DesugarVarHandle_setArrayLong(factory, setArrayLong))
+ .disableAndroidApiLevelCheck()
+ .build(),
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(getInt)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+ .setCode(DesugarVarHandle_getInt(factory, getInt))
+ .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(getLong)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+ .setCode(DesugarVarHandle_getLong(factory, getLong))
+ .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(get)
.setAccessFlags(
MethodAccessFlags.fromSharedAccessFlags(
@@ -226,11 +436,11 @@
.disableAndroidApiLevelCheck()
.build(),
DexEncodedMethod.syntheticBuilder()
- .setMethod(compareAndSet)
+ .setMethod(compareAndSetArrayInt)
.setAccessFlags(
MethodAccessFlags.fromSharedAccessFlags(
Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
- .setCode(DesugarVarHandle_compareAndSet(factory, compareAndSet))
+ .setCode(DesugarVarHandle_compareAndSetArrayInt(factory, compareAndSetArrayInt))
.disableAndroidApiLevelCheck()
.build(),
DexEncodedMethod.syntheticBuilder()
@@ -242,11 +452,21 @@
.disableAndroidApiLevelCheck()
.build(),
DexEncodedMethod.syntheticBuilder()
- .setMethod(setLong)
+ .setMethod(arrayRequiringNativeSupport)
.setAccessFlags(
MethodAccessFlags.fromSharedAccessFlags(
Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
- .setCode(DesugarVarHandle_setLong(factory, setLong))
+ .setCode(
+ DesugarVarHandle_arrayRequiringNativeSupport(
+ factory, arrayRequiringNativeSupport))
+ .disableAndroidApiLevelCheck()
+ .build(),
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(boxLongIfPossible)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+ .setCode(DesugarVarHandle_boxLongIfPossible(factory, boxLongIfPossible))
.disableAndroidApiLevelCheck()
.build(),
DexEncodedMethod.syntheticBuilder()
@@ -274,6 +494,22 @@
.disableAndroidApiLevelCheck()
.build(),
DexEncodedMethod.syntheticBuilder()
+ .setMethod(getArrayInt)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+ .setCode(DesugarVarHandle_getArrayInt(factory, getArrayInt))
+ .disableAndroidApiLevelCheck()
+ .build(),
+ DexEncodedMethod.syntheticBuilder()
+ .setMethod(setArray)
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
+ .setCode(DesugarVarHandle_setArray(factory, setArray))
+ .disableAndroidApiLevelCheck()
+ .build(),
+ DexEncodedMethod.syntheticBuilder()
.setMethod(compareAndSetInt)
.setAccessFlags(
MethodAccessFlags.fromSharedAccessFlags(
@@ -282,37 +518,19 @@
.disableAndroidApiLevelCheck()
.build(),
DexEncodedMethod.syntheticBuilder()
- .setMethod(desugarWrongMethodTypeException)
+ .setMethod(compareAndSetArray)
.setAccessFlags(
MethodAccessFlags.fromSharedAccessFlags(
Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
- .setCode(
- DesugarVarHandle_desugarWrongMethodTypeException(
- factory, desugarWrongMethodTypeException))
+ .setCode(DesugarVarHandle_compareAndSetArray(factory, compareAndSetArray))
.disableAndroidApiLevelCheck()
.build(),
DexEncodedMethod.syntheticBuilder()
- .setMethod(getInt)
+ .setMethod(getArray)
.setAccessFlags(
MethodAccessFlags.fromSharedAccessFlags(
Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
- .setCode(DesugarVarHandle_getInt(factory, getInt))
- .disableAndroidApiLevelCheck()
- .build(),
- DexEncodedMethod.syntheticBuilder()
- .setMethod(getLong)
- .setAccessFlags(
- MethodAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
- .setCode(DesugarVarHandle_getLong(factory, getLong))
- .disableAndroidApiLevelCheck()
- .build(),
- DexEncodedMethod.syntheticBuilder()
- .setMethod(getInBox)
- .setAccessFlags(
- MethodAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, false))
- .setCode(DesugarVarHandle_getInBox(factory, getInBox))
+ .setCode(DesugarVarHandle_getArray(factory, getArray))
.disableAndroidApiLevelCheck()
.build()));
}
@@ -419,10 +637,21 @@
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();
+ CfLabel label15 = new CfLabel();
+ CfLabel label16 = new CfLabel();
+ CfLabel label17 = new CfLabel();
+ CfLabel label18 = new CfLabel();
+ CfLabel label19 = new CfLabel();
return new CfCode(
method.holder,
- 3,
- 3,
+ 4,
+ 4,
ImmutableList.of(
label0,
new CfLoad(ValueType.OBJECT, 0),
@@ -473,6 +702,269 @@
factory.createType("Lsun/misc/Unsafe;"),
factory.createString("U"))),
label4,
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.classType,
+ factory.createProto(factory.booleanType),
+ factory.createString("isArray")),
+ false),
+ new CfIf(If.Type.NE, ValueType.INT, label6),
+ label5,
+ new CfNew(factory.createType("Ljava/lang/IllegalArgumentException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfNew(factory.stringBuilderType),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.voidType),
+ factory.createString("<init>")),
+ false),
+ new CfConstString(factory.createString("not an array ")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.classType,
+ factory.createProto(factory.stringType),
+ factory.createString("getSimpleName")),
+ false),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringType),
+ factory.createString("toString")),
+ false),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.createType("Ljava/lang/IllegalArgumentException;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label6,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/lang/invoke/VarHandle;")),
+ FrameType.initializedNonNullReference(factory.classType),
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/lang/reflect/Field;"))
+ })),
+ new CfLoad(ValueType.OBJECT, 1),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.classType,
+ factory.createProto(factory.classType),
+ factory.createString("getComponentType")),
+ false),
+ new CfStore(ValueType.OBJECT, 3),
+ label7,
+ new CfLoad(ValueType.OBJECT, 3),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.classType,
+ factory.createProto(factory.booleanType),
+ factory.createString("isArray")),
+ false),
+ new CfIf(If.Type.EQ, ValueType.INT, label10),
+ label8,
+ new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfNew(factory.stringBuilderType),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.voidType),
+ factory.createString("<init>")),
+ false),
+ new CfConstString(
+ factory.createString("Using a VarHandle for a multidimensional array ")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.OBJECT, 0),
+ label9,
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.createType("Ljava/lang/invoke/VarHandle;"),
+ factory.createProto(factory.stringType),
+ factory.createString("arrayRequiringNativeSupport")),
+ false),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringType),
+ factory.createString("toString")),
+ false),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.createType("Ljava/lang/UnsupportedOperationException;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label10,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/lang/invoke/VarHandle;")),
+ FrameType.initializedNonNullReference(factory.classType),
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/lang/reflect/Field;")),
+ FrameType.initializedNonNullReference(factory.classType)
+ })),
+ new CfLoad(ValueType.OBJECT, 3),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.classType,
+ factory.createProto(factory.booleanType),
+ factory.createString("isPrimitive")),
+ false),
+ new CfIf(If.Type.EQ, ValueType.INT, label14),
+ new CfLoad(ValueType.OBJECT, 3),
+ new CfStaticFieldRead(
+ factory.createField(
+ factory.createType("Ljava/lang/Integer;"),
+ factory.classType,
+ factory.createString("TYPE"))),
+ new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label14),
+ new CfLoad(ValueType.OBJECT, 3),
+ new CfStaticFieldRead(
+ factory.createField(
+ factory.createType("Ljava/lang/Long;"),
+ factory.classType,
+ factory.createString("TYPE"))),
+ new CfIfCmp(If.Type.EQ, ValueType.OBJECT, label14),
+ label11,
+ new CfNew(factory.createType("Ljava/lang/UnsupportedOperationException;")),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfNew(factory.stringBuilderType),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.voidType),
+ factory.createString("<init>")),
+ false),
+ new CfConstString(factory.createString("Using a VarHandle for an array of type '")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.OBJECT, 3),
+ label12,
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.classType,
+ factory.createProto(factory.stringType),
+ factory.createString("getName")),
+ false),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfConstString(factory.createString("' ")),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfLoad(ValueType.OBJECT, 0),
+ label13,
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.createType("Ljava/lang/invoke/VarHandle;"),
+ factory.createProto(factory.stringType),
+ factory.createString("arrayRequiringNativeSupport")),
+ false),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringBuilderType, factory.stringType),
+ factory.createString("append")),
+ false),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.stringBuilderType,
+ factory.createProto(factory.stringType),
+ factory.createString("toString")),
+ false),
+ new CfInvoke(
+ 183,
+ factory.createMethod(
+ factory.createType("Ljava/lang/UnsupportedOperationException;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("<init>")),
+ false),
+ new CfThrow(),
+ label14,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/lang/invoke/VarHandle;")),
+ FrameType.initializedNonNullReference(factory.classType),
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/lang/reflect/Field;")),
+ FrameType.initializedNonNullReference(factory.classType)
+ })),
new CfLoad(ValueType.OBJECT, 0),
new CfLoad(ValueType.OBJECT, 1),
new CfInstanceFieldWrite(
@@ -480,7 +972,7 @@
factory.createType("Ljava/lang/invoke/VarHandle;"),
factory.classType,
factory.createString("recv"))),
- label5,
+ label15,
new CfLoad(ValueType.OBJECT, 0),
new CfLoad(ValueType.OBJECT, 1),
new CfInvoke(
@@ -495,7 +987,7 @@
factory.createType("Ljava/lang/invoke/VarHandle;"),
factory.classType,
factory.createString("type"))),
- label6,
+ label16,
new CfLoad(ValueType.OBJECT, 0),
new CfLoad(ValueType.OBJECT, 0),
new CfInstanceFieldRead(
@@ -522,9 +1014,36 @@
factory.createType("Ljava/lang/invoke/VarHandle;"),
factory.longType,
factory.createString("offset"))),
- label7,
+ label17,
+ 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, 0),
+ new CfInstanceFieldRead(
+ factory.createField(
+ factory.createType("Ljava/lang/invoke/VarHandle;"),
+ factory.classType,
+ factory.createString("recv"))),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.createType("Lsun/misc/Unsafe;"),
+ factory.createProto(factory.intType, factory.classType),
+ factory.createString("arrayIndexScale")),
+ false),
+ new CfNumberConversion(NumericType.INT, NumericType.LONG),
+ new CfInstanceFieldWrite(
+ factory.createField(
+ factory.createType("Ljava/lang/invoke/VarHandle;"),
+ factory.longType,
+ factory.createString("arrayIndexScale"))),
+ label18,
new CfReturnVoid(),
- label8),
+ label19),
ImmutableList.of(),
ImmutableList.of());
}
@@ -543,6 +1062,7 @@
CfLabel label10 = new CfLabel();
CfLabel label11 = new CfLabel();
CfLabel label12 = new CfLabel();
+ CfLabel label13 = new CfLabel();
return new CfCode(
method.holder,
4,
@@ -764,8 +1284,218 @@
factory.longType,
factory.createString("offset"))),
label11,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfConstNumber(0, ValueType.LONG),
+ new CfInstanceFieldWrite(
+ factory.createField(
+ factory.createType("Ljava/lang/invoke/VarHandle;"),
+ factory.longType,
+ factory.createString("arrayIndexScale"))),
+ label12,
new CfReturnVoid(),
- label12),
+ label13),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode DesugarVarHandle_arrayRequiringNativeSupport(
+ DexItemFactory factory, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 1,
+ 1,
+ ImmutableList.of(
+ label0,
+ new CfConstString(
+ factory.createString(
+ "requires native VarHandle support available from Android 13. VarHandle"
+ + " desugaring only supports single dimensional arrays of primitive"
+ + " typesint and long and reference types.")),
+ new CfReturn(ValueType.OBJECT),
+ label1),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode DesugarVarHandle_boxIntIfPossible(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();
+ return new CfCode(
+ method.holder,
+ 2,
+ 3,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfConstClass(factory.createType("Ljava/lang/Long;")),
+ new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+ label1,
+ new CfLoad(ValueType.INT, 1),
+ new CfNumberConversion(NumericType.INT, NumericType.LONG),
+ 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),
+ label2,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/lang/invoke/VarHandle;")),
+ FrameType.intType(),
+ FrameType.initializedNonNullReference(factory.classType)
+ })),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfConstClass(factory.createType("Ljava/lang/Float;")),
+ new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+ label3,
+ new CfLoad(ValueType.INT, 1),
+ new CfNumberConversion(NumericType.INT, NumericType.FLOAT),
+ new CfInvoke(
+ 184,
+ factory.createMethod(
+ factory.createType("Ljava/lang/Float;"),
+ factory.createProto(factory.createType("Ljava/lang/Float;"), factory.floatType),
+ factory.createString("valueOf")),
+ 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.intType(),
+ FrameType.initializedNonNullReference(factory.classType)
+ })),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfConstClass(factory.createType("Ljava/lang/Double;")),
+ new CfIfCmp(If.Type.NE, ValueType.OBJECT, label6),
+ label5,
+ new CfLoad(ValueType.INT, 1),
+ new CfNumberConversion(NumericType.INT, NumericType.DOUBLE),
+ new CfInvoke(
+ 184,
+ factory.createMethod(
+ factory.createType("Ljava/lang/Double;"),
+ factory.createProto(
+ factory.createType("Ljava/lang/Double;"), factory.doubleType),
+ factory.createString("valueOf")),
+ false),
+ new CfReturn(ValueType.OBJECT),
+ label6,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/lang/invoke/VarHandle;")),
+ FrameType.intType(),
+ FrameType.initializedNonNullReference(factory.classType)
+ })),
+ 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(),
+ label7),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode DesugarVarHandle_boxLongIfPossible(
+ 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,
+ 2,
+ 4,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.OBJECT, 3),
+ new CfConstClass(factory.createType("Ljava/lang/Float;")),
+ new CfIfCmp(If.Type.NE, ValueType.OBJECT, label2),
+ label1,
+ new CfLoad(ValueType.LONG, 1),
+ new CfNumberConversion(NumericType.LONG, NumericType.FLOAT),
+ new CfInvoke(
+ 184,
+ factory.createMethod(
+ factory.createType("Ljava/lang/Float;"),
+ factory.createProto(factory.createType("Ljava/lang/Float;"), factory.floatType),
+ factory.createString("valueOf")),
+ false),
+ new CfReturn(ValueType.OBJECT),
+ label2,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/lang/invoke/VarHandle;")),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.initializedNonNullReference(factory.classType)
+ })),
+ new CfLoad(ValueType.OBJECT, 3),
+ new CfConstClass(factory.createType("Ljava/lang/Double;")),
+ new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+ label3,
+ new CfLoad(ValueType.LONG, 1),
+ new CfNumberConversion(NumericType.LONG, NumericType.DOUBLE),
+ new CfInvoke(
+ 184,
+ factory.createMethod(
+ factory.createType("Ljava/lang/Double;"),
+ factory.createProto(
+ factory.createType("Ljava/lang/Double;"), factory.doubleType),
+ factory.createString("valueOf")),
+ false),
+ new CfReturn(ValueType.OBJECT),
+ label4,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/lang/invoke/VarHandle;")),
+ FrameType.longType(),
+ FrameType.longHighType(),
+ FrameType.initializedNonNullReference(factory.classType)
+ })),
+ 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(),
+ label5),
ImmutableList.of(),
ImmutableList.of());
}
@@ -964,6 +1694,454 @@
ImmutableList.of());
}
+ public static CfCode DesugarVarHandle_compareAndSetArray(
+ 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_compareAndSetArrayInt(
+ 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_compareAndSetArrayLong(
+ 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_compareAndSetInt(DexItemFactory factory, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
@@ -1384,7 +2562,218 @@
ImmutableList.of());
}
- public static CfCode DesugarVarHandle_getInBox(DexItemFactory factory, DexMethod method) {
+ public static CfCode DesugarVarHandle_getArray(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("getInt")),
+ 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("getLong")),
+ 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("getObject")),
+ false),
+ new CfReturn(ValueType.OBJECT),
+ label8),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode DesugarVarHandle_getArrayInBox(DexItemFactory factory, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
CfLabel label2 = new CfLabel();
@@ -1399,13 +2788,306 @@
CfLabel label11 = new CfLabel();
CfLabel label12 = new CfLabel();
CfLabel label13 = new CfLabel();
- CfLabel label14 = new CfLabel();
- CfLabel label15 = new CfLabel();
- CfLabel label16 = new CfLabel();
- CfLabel label17 = new CfLabel();
return new CfCode(
method.holder,
- 4,
+ 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("getInt")),
+ 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("getLong")),
+ 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("getObject")),
+ 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_getArrayInt(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,
@@ -1414,15 +3096,177 @@
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("getInt")),
+ false),
+ new CfReturn(ValueType.INT),
+ label4),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode DesugarVarHandle_getArrayLong(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("getLong")),
+ false),
+ new CfReturn(ValueType.LONG),
+ label4),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode DesugarVarHandle_getInBox(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, label9),
+ 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;"),
@@ -1442,94 +3286,16 @@
factory.createProto(factory.intType, factory.objectType, factory.longType),
factory.createString("getInt")),
false),
- new CfStore(ValueType.INT, 3),
- label2,
new CfLoad(ValueType.OBJECT, 2),
- new CfConstClass(factory.createType("Ljava/lang/Long;")),
- new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
- label3,
- new CfLoad(ValueType.INT, 3),
- new CfNumberConversion(NumericType.INT, NumericType.LONG),
- 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, 2, 3},
- new FrameType[] {
- FrameType.initializedNonNullReference(
- factory.createType("Ljava/lang/invoke/VarHandle;")),
- FrameType.initializedNonNullReference(factory.objectType),
- FrameType.initializedNonNullReference(factory.classType),
- FrameType.intType()
- })),
- new CfLoad(ValueType.OBJECT, 2),
- new CfConstClass(factory.createType("Ljava/lang/Float;")),
- new CfIfCmp(If.Type.NE, ValueType.OBJECT, label6),
- label5,
- new CfLoad(ValueType.INT, 3),
- new CfNumberConversion(NumericType.INT, NumericType.FLOAT),
- new CfInvoke(
- 184,
- factory.createMethod(
- factory.createType("Ljava/lang/Float;"),
- factory.createProto(factory.createType("Ljava/lang/Float;"), factory.floatType),
- factory.createString("valueOf")),
- false),
- new CfReturn(ValueType.OBJECT),
- label6,
- 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.classType),
- FrameType.intType()
- })),
- new CfLoad(ValueType.OBJECT, 2),
- new CfConstClass(factory.createType("Ljava/lang/Double;")),
- new CfIfCmp(If.Type.NE, ValueType.OBJECT, label8),
- label7,
- new CfLoad(ValueType.INT, 3),
- new CfNumberConversion(NumericType.INT, NumericType.DOUBLE),
- new CfInvoke(
- 184,
- factory.createMethod(
- factory.createType("Ljava/lang/Double;"),
- factory.createProto(
- factory.createType("Ljava/lang/Double;"), factory.doubleType),
- factory.createString("valueOf")),
- false),
- new CfReturn(ValueType.OBJECT),
- 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.classType),
- FrameType.intType()
- })),
- 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")),
+ factory.createProto(factory.objectType, factory.intType, factory.classType),
+ factory.createString("boxIntIfPossible")),
false),
- new CfThrow(),
- label9,
+ new CfReturn(ValueType.OBJECT),
+ label2,
new CfFrame(
new Int2ObjectAVLTreeMap<>(
new int[] {0, 1, 2},
@@ -1550,8 +3316,9 @@
factory.createType("Ljava/lang/Long;"),
factory.classType,
factory.createString("TYPE"))),
- new CfIfCmp(If.Type.NE, ValueType.OBJECT, label16),
- label10,
+ new CfIfCmp(If.Type.NE, ValueType.OBJECT, label4),
+ label3,
+ new CfLoad(ValueType.OBJECT, 0),
new CfLoad(ValueType.OBJECT, 0),
new CfInstanceFieldRead(
factory.createField(
@@ -1572,71 +3339,16 @@
factory.createProto(factory.longType, factory.objectType, factory.longType),
factory.createString("getLong")),
false),
- new CfStore(ValueType.LONG, 3),
- label11,
new CfLoad(ValueType.OBJECT, 2),
- new CfConstClass(factory.createType("Ljava/lang/Float;")),
- new CfIfCmp(If.Type.NE, ValueType.OBJECT, label13),
- label12,
- new CfLoad(ValueType.LONG, 3),
- new CfNumberConversion(NumericType.LONG, NumericType.FLOAT),
- new CfInvoke(
- 184,
- factory.createMethod(
- factory.createType("Ljava/lang/Float;"),
- factory.createProto(factory.createType("Ljava/lang/Float;"), factory.floatType),
- factory.createString("valueOf")),
- false),
- new CfReturn(ValueType.OBJECT),
- label13,
- 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.initializedNonNullReference(factory.classType),
- FrameType.longType(),
- FrameType.longHighType()
- })),
- new CfLoad(ValueType.OBJECT, 2),
- new CfConstClass(factory.createType("Ljava/lang/Double;")),
- new CfIfCmp(If.Type.NE, ValueType.OBJECT, label15),
- label14,
- new CfLoad(ValueType.LONG, 3),
- new CfNumberConversion(NumericType.LONG, NumericType.DOUBLE),
- new CfInvoke(
- 184,
- factory.createMethod(
- factory.createType("Ljava/lang/Double;"),
- factory.createProto(
- factory.createType("Ljava/lang/Double;"), factory.doubleType),
- factory.createString("valueOf")),
- false),
- new CfReturn(ValueType.OBJECT),
- label15,
- 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.initializedNonNullReference(factory.classType),
- FrameType.longType(),
- FrameType.longHighType()
- })),
- 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")),
+ factory.createProto(factory.objectType, factory.longType, factory.classType),
+ factory.createString("boxLongIfPossible")),
false),
- new CfThrow(),
- label16,
+ new CfReturn(ValueType.OBJECT),
+ label4,
new CfFrame(
new Int2ObjectAVLTreeMap<>(
new int[] {0, 1, 2},
@@ -1667,7 +3379,7 @@
factory.createString("getObject")),
false),
new CfReturn(ValueType.OBJECT),
- label17),
+ label5),
ImmutableList.of(),
ImmutableList.of());
}
@@ -2067,6 +3779,407 @@
ImmutableList.of());
}
+ public static CfCode DesugarVarHandle_setArray(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("putInt")),
+ 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("putLong")),
+ 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("putObject")),
+ 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_setArrayInt(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("putInt")),
+ false),
+ label4,
+ new CfReturnVoid(),
+ label5),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
+ public static CfCode DesugarVarHandle_setArrayLong(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("putLong")),
+ false),
+ label4,
+ new CfReturnVoid(),
+ label5),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
+
public static CfCode DesugarVarHandle_setInt(DexItemFactory factory, DexMethod method) {
CfLabel label0 = new CfLabel();
CfLabel label1 = new CfLabel();
diff --git a/src/test/examplesJava9/varhandle/ArrayOfInt.java b/src/test/examplesJava9/varhandle/ArrayOfInt.java
index dc5ea71..c63f79d 100644
--- a/src/test/examplesJava9/varhandle/ArrayOfInt.java
+++ b/src/test/examplesJava9/varhandle/ArrayOfInt.java
@@ -8,7 +8,235 @@
public class ArrayOfInt {
- public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
+ private static void checkJavaLangInvokeWrongMethodTypeException(RuntimeException e) {
+ if (e.getClass().getCanonicalName().equals("java.lang.invoke.WrongMethodTypeException")
+ || e.getMessage().equals("java.lang.invoke.WrongMethodTypeException")) {
+ return;
+ }
+ throw e;
+ }
+
+ public static void testGet() {
+ System.out.println("testGet");
+ 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.get(array, 0));
+ System.out.println(arrayVarHandle.get(array, 1));
+ System.out.println((Object) arrayVarHandle.get(array, 0));
+ System.out.println((Object) arrayVarHandle.get(array, 1));
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ System.out.println((float) arrayVarHandle.get(array, 0));
+ System.out.println((float) arrayVarHandle.get(array, 1));
+ System.out.println((double) arrayVarHandle.get(array, 0));
+ System.out.println((double) arrayVarHandle.get(array, 1));
+ try {
+ System.out.println((boolean) arrayVarHandle.get(array, 0));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((boolean) arrayVarHandle.get(array, 1));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((byte) arrayVarHandle.get(array, 0));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((byte) arrayVarHandle.get(array, 1));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((short) arrayVarHandle.get(array, 0));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((short) arrayVarHandle.get(array, 1));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((char) arrayVarHandle.get(array, 0));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((char) arrayVarHandle.get(array, 1));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((String) arrayVarHandle.get(array, 0));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((String) arrayVarHandle.get(array, 1));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ }
+
+ public static void testSet() {
+ System.out.println("testSet");
+
+ VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(int[].class);
+ int[] array = new int[2];
+
+ // int and Integer values.
+ arrayVarHandle.set(array, 0, 1);
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, 2);
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, Integer.valueOf(3));
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(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.set(array, 0, (byte) 5);
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, (byte) 6);
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, Byte.valueOf((byte) 7));
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, Byte.valueOf((byte) 8));
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, '0');
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, '1');
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, Character.valueOf('2'));
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, Character.valueOf('3'));
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, (short) 9);
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, (short) 10);
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, Short.valueOf((short) 11));
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(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.set(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.set(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.set(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.set(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.set(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.set(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.set(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.set(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.set(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 void testCompareAndSet() {
VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(int[].class);
int[] array = new int[2];
arrayVarHandle.set(array, 0, 1);
@@ -20,10 +248,32 @@
arrayVarHandle.compareAndSet(array, 1, 0, 2);
System.out.println((int) arrayVarHandle.get(array, 0));
System.out.println((int) arrayVarHandle.get(array, 1));
- // TODO(sgjesse): Handle boxed.
+ // TODO(b/247076137): Handle boxed.
// arrayVarHandle.compareAndSet(array, 1, 2, box(3));
arrayVarHandle.compareAndSet(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 {
+ MethodHandles.arrayElementVarHandle(int.class);
+ System.out.println("Unexpected success");
+ } catch (IllegalArgumentException e) {
+ System.out.println("IllegalArgumentException");
+ }
+ try {
+ MethodHandles.arrayElementVarHandle(int[][].class);
+ System.out.println("Got array element VarHandle");
+ } catch (UnsupportedOperationException e) {
+ System.out.println("UnsupportedOperationException");
+ }
+ }
+
+ public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
+ testGet();
+ testSet();
+ testArrayVarHandleForNonSingleDimension();
+ }
}
diff --git a/src/test/examplesJava9/varhandle/ArrayOfLong.java b/src/test/examplesJava9/varhandle/ArrayOfLong.java
index 5d3e550..c909319 100644
--- a/src/test/examplesJava9/varhandle/ArrayOfLong.java
+++ b/src/test/examplesJava9/varhandle/ArrayOfLong.java
@@ -8,22 +8,259 @@
public class ArrayOfLong {
- public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
+ private static void checkJavaLangInvokeWrongMethodTypeException(RuntimeException e) {
+ if (e.getClass().getCanonicalName().equals("java.lang.invoke.WrongMethodTypeException")
+ || e.getMessage().equals("java.lang.invoke.WrongMethodTypeException")) {
+ return;
+ }
+ throw e;
+ }
+
+ public static void testGet() {
+ System.out.println("testGet");
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.get(array, 0));
+ System.out.println(arrayVarHandle.get(array, 1));
+ System.out.println((Object) arrayVarHandle.get(array, 0));
+ System.out.println((Object) arrayVarHandle.get(array, 1));
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ System.out.println((float) arrayVarHandle.get(array, 0));
+ System.out.println((float) arrayVarHandle.get(array, 1));
+ System.out.println((double) arrayVarHandle.get(array, 0));
+ System.out.println((double) arrayVarHandle.get(array, 1));
+ try {
+ System.out.println((boolean) arrayVarHandle.get(array, 0));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((boolean) arrayVarHandle.get(array, 1));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((byte) arrayVarHandle.get(array, 0));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((byte) arrayVarHandle.get(array, 1));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((short) arrayVarHandle.get(array, 0));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((short) arrayVarHandle.get(array, 1));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((char) arrayVarHandle.get(array, 0));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((char) arrayVarHandle.get(array, 1));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((String) arrayVarHandle.get(array, 0));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ try {
+ System.out.println((String) arrayVarHandle.get(array, 1));
+ System.out.println("Unexpected success");
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ }
+
+ public static void testSet() {
+ System.out.println("testSet");
+
+ VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(long[].class);
+ long[] array = new long[2];
+
+ // long and Long values.
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);
+ arrayVarHandle.set(array, 1, 2L);
System.out.println((long) arrayVarHandle.get(array, 0));
System.out.println((long) arrayVarHandle.get(array, 1));
- arrayVarHandle.compareAndSet(array, 1, 0L, 2L);
+ arrayVarHandle.set(array, 0, Long.valueOf(3L));
System.out.println((long) arrayVarHandle.get(array, 0));
System.out.println((long) arrayVarHandle.get(array, 1));
- // TODO(sgjesse): Handle boxed.
- // arrayVarHandle.compareAndSet(array, 1, 2, box(3));
- arrayVarHandle.compareAndSet(array, 1, 2L, 3L);
+ arrayVarHandle.set(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.set(array, 0, (byte) 5);
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, (byte) 6);
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, Byte.valueOf((byte) 7));
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, Byte.valueOf((byte) 8));
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, '0');
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, '1');
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, Character.valueOf('2'));
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, Character.valueOf('3'));
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, (short) 9);
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, (short) 10);
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, Short.valueOf((short) 11));
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, Short.valueOf((short) 12));
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, 13);
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 1, 14);
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(array, 0, Integer.valueOf(15));
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ arrayVarHandle.set(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.set(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.set(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.set(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.set(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.set(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.set(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.set(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 testArrayVarHandleForNonSingleDimension() {
+ System.out.println("testArrayVarHandleForNonSingleDimension");
+ try {
+ MethodHandles.arrayElementVarHandle(int.class);
+ System.out.println("Unexpected success");
+ } catch (IllegalArgumentException e) {
+ System.out.println("IllegalArgumentException");
+ }
+ try {
+ MethodHandles.arrayElementVarHandle(int[][].class);
+ System.out.println("Got array element VarHandle");
+ } catch (UnsupportedOperationException e) {
+ System.out.println("UnsupportedOperationException");
+ }
+ }
+
+ public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
+ testGet();
+ testSet();
+ testArrayVarHandleForNonSingleDimension();
}
}
diff --git a/src/test/examplesJava9/varhandle/ArrayOfObject.java b/src/test/examplesJava9/varhandle/ArrayOfObject.java
new file mode 100644
index 0000000..ab9a6bd
--- /dev/null
+++ b/src/test/examplesJava9/varhandle/ArrayOfObject.java
@@ -0,0 +1,373 @@
+// 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 varhandle;
+
+import java.lang.invoke.MethodHandles;
+import java.lang.invoke.VarHandle;
+
+public class ArrayOfObject {
+
+ public static class A {
+
+ private final int i;
+
+ public A(int i) {
+ this.i = i;
+ }
+
+ public String toString() {
+ return "A(" + i + ")";
+ }
+ }
+
+ private static void checkJavaLangInvokeWrongMethodTypeException(RuntimeException e) {
+ if (e.getClass().getCanonicalName().equals("java.lang.invoke.WrongMethodTypeException")
+ || e.getMessage().equals("java.lang.invoke.WrongMethodTypeException")) {
+ return;
+ }
+ throw e;
+ }
+
+ public static void unsupportedGetConversion(VarHandle arrayVarHandle, Object[] array) {
+ try {
+ System.out.println((boolean) arrayVarHandle.get(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.get(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.get(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.get(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.get(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.get(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.get(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.get(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.get(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.get(array, 1));
+ System.out.println("Unexpected success");
+ } catch (ClassCastException e) {
+ // The reference implementation throws ClassCastException.
+ } catch (RuntimeException e) {
+ checkJavaLangInvokeWrongMethodTypeException(e);
+ }
+ }
+
+ public static void testGet() {
+ System.out.println("testGet");
+ 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.get(array, 0));
+ System.out.println(arrayVarHandle.get(array, 1));
+ System.out.println((Object) arrayVarHandle.get(array, 0));
+ System.out.println((Object) arrayVarHandle.get(array, 1));
+ System.out.println((int) arrayVarHandle.get(array, 0));
+ System.out.println((int) arrayVarHandle.get(array, 1));
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ System.out.println((float) arrayVarHandle.get(array, 0));
+ System.out.println((float) arrayVarHandle.get(array, 1));
+ System.out.println((double) arrayVarHandle.get(array, 0));
+ System.out.println((double) arrayVarHandle.get(array, 1));
+ unsupportedGetConversion(arrayVarHandle, array);
+
+ arrayVarHandle.set(array, 0, 3L);
+ arrayVarHandle.set(array, 1, 4L);
+
+ System.out.println(arrayVarHandle.get(array, 0));
+ System.out.println(arrayVarHandle.get(array, 1));
+ System.out.println((Object) arrayVarHandle.get(array, 0));
+ System.out.println((Object) arrayVarHandle.get(array, 1));
+ System.out.println((long) arrayVarHandle.get(array, 0));
+ System.out.println((long) arrayVarHandle.get(array, 1));
+ System.out.println((float) arrayVarHandle.get(array, 0));
+ System.out.println((float) arrayVarHandle.get(array, 1));
+ System.out.println((double) arrayVarHandle.get(array, 0));
+ System.out.println((double) arrayVarHandle.get(array, 1));
+ unsupportedGetConversion(arrayVarHandle, array);
+ try {
+ System.out.println((int) arrayVarHandle.get(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.get(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");
+
+ VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(Object[].class);
+ Object[] array = new Object[2];
+
+ Object o;
+ {
+ int index = 0;
+ byte b;
+ arrayVarHandle.set(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.set(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.set(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.set(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.set(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.set(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.set(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.set(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.set(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.set(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");
+
+ VarHandle arrayVarHandle = MethodHandles.arrayElementVarHandle(Object[].class);
+ Object[] array = new Object[2];
+
+ int index = 0;
+ A a1 = new A(1);
+ arrayVarHandle.compareAndSet(array, index, 0, a1);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(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.compareAndSet(array, index, a1, a2);
+ System.out.println(arrayVarHandle.get(array, index));
+ System.out.println(arrayVarHandle.get(array, index) == a2);
+
+ arrayVarHandle.compareAndSet(array, index, a2, 1);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, Integer.valueOf(1), 2);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, Integer.valueOf(2), Integer.valueOf(3));
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, Integer.valueOf(3), 4);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, 4L, 5);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, (byte) 4, 5);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, (short) 4, 5);
+ System.out.println(arrayVarHandle.get(array, index));
+
+ arrayVarHandle.compareAndSet(array, index, 4, 5L);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, Long.valueOf(5), 6L);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, Long.valueOf(6), Long.valueOf(7));
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, Long.valueOf(7), 8L);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, 8, 9L);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, (byte) 8, 9);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, (short) 8, 9);
+ System.out.println(arrayVarHandle.get(array, index));
+ System.out.println(arrayVarHandle.get(array, index) == a1);
+ arrayVarHandle.compareAndSet(array, index, a1, a2);
+ System.out.println(arrayVarHandle.get(array, index));
+ System.out.println(arrayVarHandle.get(array, index) == a2);
+
+ arrayVarHandle.compareAndSet(array, index, a2, 1);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, Integer.valueOf(1), 2);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, Integer.valueOf(2), Integer.valueOf(3));
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, Integer.valueOf(3), 4);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, 4L, 5);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, (byte) 4, 5);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, (short) 4, 5);
+ System.out.println(arrayVarHandle.get(array, index));
+
+ arrayVarHandle.compareAndSet(array, index, 4, 5L);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, Long.valueOf(5), 6L);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, Long.valueOf(6), Long.valueOf(7));
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, Long.valueOf(7), 8L);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, 8, 9L);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, (byte) 8, 9);
+ System.out.println(arrayVarHandle.get(array, index));
+ arrayVarHandle.compareAndSet(array, index, (short) 8, 9);
+ System.out.println(arrayVarHandle.get(array, index));
+ }
+
+ public static void testArrayVarHandleForNonSingleDimension() {
+ System.out.println("testArrayVarHandleForNonSingleDimension");
+ try {
+ MethodHandles.arrayElementVarHandle(Object.class);
+ System.out.println("Unexpected success");
+ } catch (IllegalArgumentException e) {
+ System.out.println("IllegalArgumentException");
+ }
+ try {
+ MethodHandles.arrayElementVarHandle(Object[][].class);
+ System.out.println("Got array element VarHandle");
+ } catch (UnsupportedOperationException e) {
+ System.out.println("UnsupportedOperationException");
+ }
+ }
+
+ public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
+ testGet();
+ testSet();
+ testCompareAndSet();
+ testArrayVarHandleForNonSingleDimension();
+ }
+}
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 d7ca20f..db63206 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
@@ -15,7 +15,74 @@
public class VarHandleDesugaringArrayOfIntTest extends VarHandleDesugaringTestBase {
private static final String EXPECTED_OUTPUT =
- StringUtils.lines("1", "0", "1", "0", "1", "2", "1", "3");
+ StringUtils.lines(
+ "testGet",
+ "1",
+ "2",
+ "1",
+ "2",
+ "1",
+ "2",
+ "1",
+ "2",
+ "1.0",
+ "2.0",
+ "1.0",
+ "2.0",
+ "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",
+ "testArrayVarHandleForNonSingleDimension",
+ "IllegalArgumentException");
+
private static final String MAIN_CLASS = VarHandle.ArrayOfInt.typeName();
private static final String JAR_ENTRY = "varhandle/ArrayOfInt.class";
@@ -31,6 +98,11 @@
@Override
protected String getExpectedOutputForReferenceImplementation() {
- return EXPECTED_OUTPUT;
+ return StringUtils.lines(EXPECTED_OUTPUT.trim(), "Got array element VarHandle");
+ }
+
+ @Override
+ protected String getExpectedOutputForDesugaringImplementation() {
+ return StringUtils.lines(EXPECTED_OUTPUT.trim(), "UnsupportedOperationException");
}
}
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 c3c81da..3867f1c 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
@@ -15,7 +15,76 @@
public class VarHandleDesugaringArrayOfLongTest extends VarHandleDesugaringTestBase {
private static final String EXPECTED_OUTPUT =
- StringUtils.lines("1", "0", "1", "0", "1", "2", "1", "3");
+ StringUtils.lines(
+ "testGet",
+ "1",
+ "2",
+ "1",
+ "2",
+ "1",
+ "2",
+ "1.0",
+ "2.0",
+ "1.0",
+ "2.0",
+ "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",
+ "testArrayVarHandleForNonSingleDimension",
+ "IllegalArgumentException");
+
private static final String MAIN_CLASS = VarHandle.ArrayOfLong.typeName();
private static final String JAR_ENTRY = "varhandle/ArrayOfLong.class";
@@ -31,6 +100,11 @@
@Override
protected String getExpectedOutputForReferenceImplementation() {
- return EXPECTED_OUTPUT;
+ return StringUtils.lines(EXPECTED_OUTPUT.trim(), "Got array element VarHandle");
+ }
+
+ @Override
+ protected String getExpectedOutputForDesugaringImplementation() {
+ return StringUtils.lines(EXPECTED_OUTPUT.trim(), "UnsupportedOperationException");
}
}
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
new file mode 100644
index 0000000..72439ec
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/varhandle/VarHandleDesugaringArrayOfObjectTest.java
@@ -0,0 +1,146 @@
+// 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.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 VarHandleDesugaringArrayOfObjectTest extends VarHandleDesugaringTestBase {
+
+ 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",
+ "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",
+ "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",
+ "testArrayVarHandleForNonSingleDimension",
+ "IllegalArgumentException");
+
+ private static final String MAIN_CLASS = VarHandle.ArrayOfObject.typeName();
+ private static final List<String> JAR_ENTRIES =
+ ImmutableList.of("varhandle/ArrayOfObject.class", "varhandle/ArrayOfObject$A.class");
+
+ @Override
+ protected String getMainClass() {
+ return MAIN_CLASS;
+ }
+
+ @Override
+ protected List<String> getJarEntries() {
+ return JAR_ENTRIES;
+ }
+
+ @Override
+ protected String getExpectedOutputForReferenceImplementation() {
+ return StringUtils.lines(EXPECTED_OUTPUT.trim(), "Got array element VarHandle");
+ }
+
+ @Override
+ protected String getExpectedOutputForDesugaringImplementation() {
+ return StringUtils.lines(EXPECTED_OUTPUT.trim(), "UnsupportedOperationException");
+ }
+}
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 d9fc4c4..5c84a74 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
@@ -54,9 +54,4 @@
protected String getExpectedOutputForDesugaringImplementation() {
return StringUtils.lines("Got UnsupportedOperationException");
}
-
- @Override
- protected boolean getTestWithDesugaring() {
- return true;
- }
}
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 a96b5a9..a2f3b1d 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
@@ -44,9 +44,4 @@
protected String getExpectedOutputForDesugaringImplementation() {
return StringUtils.lines("Got UnsupportedOperationException");
}
-
- @Override
- protected boolean getTestWithDesugaring() {
- return true;
- }
}
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 194f25f..9eccf94 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
@@ -45,9 +45,4 @@
protected String getExpectedOutputForDesugaringImplementation() {
return StringUtils.lines("Got UnsupportedOperationException");
}
-
- @Override
- protected boolean getTestWithDesugaring() {
- return true;
- }
}
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 457753b..db95c14 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
@@ -45,9 +45,4 @@
protected String getExpectedOutputForDesugaringImplementation() {
return StringUtils.lines("Got UnsupportedOperationException");
}
-
- @Override
- protected boolean getTestWithDesugaring() {
- return true;
- }
}
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 f676891..1969ffb 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
@@ -93,9 +93,4 @@
protected String getExpectedOutputForReferenceImplementation() {
return EXPECTED_OUTPUT;
}
-
- @Override
- protected boolean getTestWithDesugaring() {
- return true;
- }
}
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 7303ec5..9794153 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
@@ -91,9 +91,4 @@
protected String getExpectedOutputForReferenceImplementation() {
return EXPECTED_OUTPUT;
}
-
- @Override
- protected boolean getTestWithDesugaring() {
- return true;
- }
}
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 ac43573..a7b2a30 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
@@ -147,9 +147,4 @@
assert parameters.isDexRuntime();
return StringUtils.lines(EXPECTED_OUTPUT.trim(), "Art implementation", "Art implementation");
}
-
- @Override
- protected boolean getTestWithDesugaring() {
- return true;
- }
}
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 a5947eb..e52df14 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
@@ -44,9 +44,4 @@
protected String getExpectedOutputForDesugaringImplementation() {
return StringUtils.lines("Got UnsupportedOperationException");
}
-
- @Override
- protected boolean getTestWithDesugaring() {
- return true;
- }
}
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 f1440c1..e1beca1 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
@@ -50,9 +50,4 @@
protected String getExpectedOutputForReferenceImplementation() {
return EXPECTED_OUTPUT;
}
-
- @Override
- protected boolean getTestWithDesugaring() {
- return true;
- }
}
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 bb4d99b..d8b0543 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
@@ -72,11 +72,6 @@
return getExpectedOutputForReferenceImplementation();
}
- // TODO(b/247076137): Remove this when all tests can run with desugaring.
- protected boolean getTestWithDesugaring() {
- return false;
- }
-
@Test
public void testReference() throws Throwable {
assumeTrue(parameters.isCfRuntime());
@@ -168,8 +163,8 @@
});
});
if (willDesugarVarHandle()) {
- assertEquals(2, unsafeCompareAndSwapInt.get());
- assertEquals(3, unsafeCompareAndSwapLong.get());
+ assertEquals(4, unsafeCompareAndSwapInt.get());
+ assertEquals(5, unsafeCompareAndSwapLong.get());
assertEquals(1, unsafeCompareAndSwapObject.get());
} else {
assertEquals(0, unsafeCompareAndSwapInt.get());
@@ -182,42 +177,24 @@
@Test
public void testD8() throws Throwable {
assumeTrue(parameters.isDexRuntime());
- if (getTestWithDesugaring()) {
- testForD8(parameters.getBackend())
- .addProgramClassFileData(getProgramClassFileData())
- .setMinApi(parameters.getApiLevel())
- .addOptionsModification(options -> options.enableVarHandleDesugaring = true)
- .run(parameters.getRuntime(), getMainClass())
- .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(
- parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.T)
- && parameters
- .getDexRuntimeVersion()
- .isNewerThanOrEqual(Version.V13_0_0)
- ? getExpectedOutputForArtImplementation()
- : getExpectedOutputForDesugaringImplementation()))
- .inspect(this::inspect);
- } else {
- testForD8(parameters.getBackend())
- .addProgramClassFileData(getProgramClassFileData())
- .setMinApi(parameters.getApiLevel())
- .run(parameters.getRuntime(), getMainClass())
- .applyIf(
- // VarHandle is available from Android 9, even though it was not a public API until
- // 13.
- parameters.asDexRuntime().getVersion().isOlderThanOrEqual(Version.V7_0_0),
- r -> r.assertFailureWithErrorThatThrows(NoClassDefFoundError.class),
- parameters.getApiLevel().isLessThan(AndroidApiLevel.P)
- || parameters.asDexRuntime().getVersion().isOlderThanOrEqual(Version.V8_1_0),
- r -> r.assertFailure(),
- r -> r.assertSuccessWithOutput(getExpectedOutputForArtImplementation()));
- }
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(getProgramClassFileData())
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(options -> options.enableVarHandleDesugaring = true)
+ .run(parameters.getRuntime(), getMainClass())
+ .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(
+ parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.T)
+ && parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V13_0_0)
+ ? getExpectedOutputForArtImplementation()
+ : getExpectedOutputForDesugaringImplementation()))
+ .inspect(this::inspect);
}
// TODO(b/247076137: Also turn on VarHandle desugaring for R8 tests.
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 0cb3d7f..cb2caed 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
@@ -18,6 +18,8 @@
new JavaExampleClassProxy(EXAMPLE_FILE, "varhandle/ArrayOfInt");
public static final JavaExampleClassProxy ArrayOfLong =
new JavaExampleClassProxy(EXAMPLE_FILE, "varhandle/ArrayOfLong");
+ public static final JavaExampleClassProxy ArrayOfObject =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "varhandle/ArrayOfObject");
public static final JavaExampleClassProxy InstanceIntField =
new JavaExampleClassProxy(EXAMPLE_FILE, "varhandle/InstanceIntField");
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 2ba4cf4..c01f4e9 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
@@ -70,6 +70,7 @@
private final Class<?> recv;
private final Class<?> type;
private final long offset;
+ private final long arrayIndexScale;
DesugarVarHandle(Class<?> recv, String name, Class<?> type)
throws NoSuchFieldException, IllegalAccessException {
@@ -88,18 +89,41 @@
+ "reference types.");
}
this.offset = U.objectFieldOffset(recv.getDeclaredField(name));
+ this.arrayIndexScale = 0;
}
DesugarVarHandle(Class<?> arrayType) throws Exception {
Field theUnsafe = UnsafeStub.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
U = (UnsafeStub) theUnsafe.get(null);
+ if (!arrayType.isArray()) {
+ throw new IllegalArgumentException("not an array " + arrayType.getSimpleName());
+ }
+ Class<?> componentType = arrayType.getComponentType();
+ if (componentType.isArray()) {
+ throw new UnsupportedOperationException(
+ "Using a VarHandle for a multidimensional array " + arrayRequiringNativeSupport());
+ }
+ if (componentType.isPrimitive() && componentType != int.class && componentType != long.class) {
+ throw new UnsupportedOperationException(
+ "Using a VarHandle for an array of type '"
+ + componentType.getName()
+ + "' "
+ + arrayRequiringNativeSupport());
+ }
this.recv = arrayType;
this.type = arrayType.getComponentType();
this.offset = U.arrayBaseOffset(recv);
+ this.arrayIndexScale = U.arrayIndexScale(recv);
}
// Helpers.
+ String arrayRequiringNativeSupport() {
+ return "requires native VarHandle support available from Android 13. "
+ + "VarHandle desugaring only supports single dimensional arrays of primitive types"
+ + "int and long and reference types.";
+ }
+
RuntimeException desugarWrongMethodTypeException() {
return new RuntimeException("java.lang.invoke.WrongMethodTypeException");
}
@@ -131,6 +155,29 @@
return toIntIfPossible(value, forReturnType);
}
+ Object boxIntIfPossible(int value, Class<?> expectedBox) {
+ if (expectedBox == Long.class) {
+ return Long.valueOf(value);
+ }
+ if (expectedBox == Float.class) {
+ return Float.valueOf(value);
+ }
+ if (expectedBox == Double.class) {
+ return Double.valueOf(value);
+ }
+ throw desugarWrongMethodTypeException();
+ }
+
+ Object boxLongIfPossible(long value, Class<?> expectedBox) {
+ if (expectedBox == Float.class) {
+ return Float.valueOf(value);
+ }
+ if (expectedBox == Double.class) {
+ return Double.valueOf(value);
+ }
+ throw desugarWrongMethodTypeException();
+ }
+
// get variants.
Object get(Object ct1) {
if (type == int.class) {
@@ -144,27 +191,10 @@
Object getInBox(Object ct1, Class<?> expectedBox) {
if (type == int.class) {
- int value = U.getInt(ct1, offset);
- if (expectedBox == Long.class) {
- return Long.valueOf(value);
- }
- if (expectedBox == Float.class) {
- return Float.valueOf(value);
- }
- if (expectedBox == Double.class) {
- return Double.valueOf(value);
- }
- throw desugarWrongMethodTypeException();
+ return boxIntIfPossible(U.getInt(ct1, offset), expectedBox);
}
if (type == long.class) {
- long value = U.getLong(ct1, offset);
- if (expectedBox == Float.class) {
- return Float.valueOf(value);
- }
- if (expectedBox == Double.class) {
- return Double.valueOf(value);
- }
- throw desugarWrongMethodTypeException();
+ return boxLongIfPossible(U.getLong(ct1, offset), expectedBox);
}
return U.getObject(ct1, offset);
}
@@ -248,4 +278,126 @@
}
return compareAndSet(ct1, expectedValue, newValue);
}
+
+ // get array variants.
+ Object getArray(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.getInt(ct1, elementOffset);
+ } else if (type == long.class) {
+ return (int) U.getLong(ct1, elementOffset);
+ } else {
+ return U.getObject(ct1, elementOffset);
+ }
+ }
+
+ Object getArrayInBox(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.getInt(ct1, elementOffset), expectedBox);
+ } else if (type == long.class) {
+ return boxLongIfPossible(U.getLong(ct1, elementOffset), expectedBox);
+ } else {
+ Object value = U.getObject(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 getArrayInt(int[] ct1, int ct2) {
+ if (recv != int[].class) {
+ throw new UnsupportedOperationException();
+ }
+ long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+ return U.getInt(ct1, elementOffset);
+ }
+
+ long getArrayLong(long[] ct1, int ct2) {
+ if (recv != long[].class) {
+ throw new UnsupportedOperationException();
+ }
+ long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+ return U.getLong(ct1, elementOffset);
+ }
+
+ // get array variants.
+ void setArray(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.putInt(ct1, elementOffset, toIntIfPossible(newValue, false));
+ } else if (recv == long[].class) {
+ U.putLong(ct1, elementOffset, toLongIfPossible(newValue, false));
+ } else {
+ U.putObject(ct1, elementOffset, newValue);
+ }
+ }
+
+ void setArrayInt(int[] ct1, int ct2, int newValue) {
+ if (recv != int[].class) {
+ throw new UnsupportedOperationException();
+ }
+ long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+ U.putInt(ct1, elementOffset, newValue);
+ }
+
+ void setArrayLong(long[] ct1, int ct2, long newValue) {
+ if (recv != long[].class) {
+ throw new UnsupportedOperationException();
+ }
+ long elementOffset = offset + ((long) ct2) * arrayIndexScale;
+ U.putLong(ct1, elementOffset, newValue);
+ }
+
+ // compareAndSet array variants.
+ boolean compareAndSetArray(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);
+ }
+ }
+
+ boolean compareAndSetArrayInt(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);
+ }
+
+ boolean compareAndSetArrayLong(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 7052773..0c65df4 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
@@ -24,11 +24,13 @@
import com.android.tools.r8.utils.FileUtils;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.junit.Test;
@@ -220,12 +222,14 @@
}
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")) {
- if (name.startsWith(prefix)
- && (name.substring(prefix.length()).equals("Int")
- || name.substring(prefix.length()).equals("Long")
- || name.substring(prefix.length()).equals("InBox"))) {
- return prefix;
+ if (name.startsWith(prefix)) {
+ String postfix = name.substring(prefix.length());
+ if (postfixes.contains(postfix)) {
+ return prefix;
+ }
}
}
return name;