Merge commit '0038458ccfe18b9c1e3008f6b161258949f39d0b' into dev-release
diff --git a/build.gradle b/build.gradle
index 5d4868a..b2e669c 100644
--- a/build.gradle
+++ b/build.gradle
@@ -31,7 +31,7 @@
ext {
androidSupportVersion = '25.4.0'
- asmVersion = '9.2' // When updating update tools/asmifier.py and Toolhelper as well.
+ asmVersion = '9.3' // When updating update tools/asmifier.py and Toolhelper as well.
espressoVersion = '3.0.0'
fastutilVersion = '7.2.0'
guavaVersion = '30.1.1-jre'
diff --git a/src/library_desugar/desugar_jdk_libs.json b/src/library_desugar/desugar_jdk_libs.json
index 700ea72..59ffcc0 100644
--- a/src/library_desugar/desugar_jdk_libs.json
+++ b/src/library_desugar/desugar_jdk_libs.json
@@ -2,7 +2,7 @@
"configuration_format_version": 3,
"group_id" : "com.tools.android",
"artifact_id" : "desugar_jdk_libs",
- "version": "1.1.5",
+ "version": "1.1.6",
"required_compilation_api_level": 26,
"synthesized_library_classes_package_prefix": "j$.",
"support_all_callbacks_from_library": true,
@@ -234,9 +234,10 @@
}
],
"shrinker_config": [
+ "-keepclassmembers class j$.** extends java.io.Serializable { void <init>(); static final long serialVersionUID; java.lang.Object readResolve(); java.lang.Object writeReplace(); private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }",
- "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); private static final java.io.ObjectStreamField[] serialPersistentFields; private static final long serialVersionUID;}",
+ "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { private static final java.io.ObjectStreamField[] serialPersistentFields; }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$CounterCell { long value; }",
"-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); public static final !synthetic <fields>; }",
"-keeppackagenames j$.**",
diff --git a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
index 5f43015..b1ebcd8 100644
--- a/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/chm_only_desugar_jdk_libs.json
@@ -1,5 +1,5 @@
{
- "identifier": "com.tools.android:chm_only_desugar_jdk_libs:1.0.12",
+ "identifier": "com.tools.android:chm_only_desugar_jdk_libs:1.0.13",
"configuration_format_version": 100,
"required_compilation_api_level": 26,
"synthesized_library_classes_package_prefix": "j$.",
@@ -24,6 +24,7 @@
}
],
"shrinker_config": [
+ "-keepclassmembers class j$.** extends java.io.Serializable { void <init>(); private static final java.io.ObjectStreamField[] serialPersistentFields; static final long serialVersionUID; java.lang.Object readResolve(); java.lang.Object writeReplace(); private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$CounterCell { long value; }",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs.json b/src/library_desugar/jdk11/desugar_jdk_libs.json
index c764f31..45d529c 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs.json
@@ -233,9 +233,9 @@
}
],
"shrinker_config": [
+ "-keepclassmembers class j$.** extends java.io.Serializable { void <init>(); private static final java.io.ObjectStreamField[] serialPersistentFields; static final long serialVersionUID; java.lang.Object readResolve(); java.lang.Object writeReplace(); private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }",
- "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); private static final java.io.ObjectStreamField[] serialPersistentFields; private static final long serialVersionUID;}",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$CounterCell { long value; }",
"-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); public static final !synthetic <fields>; }",
"-keeppackagenames java.**",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json b/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
index b92af9f..222feda 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_legacy.json
@@ -211,9 +211,9 @@
}
],
"shrinker_config": [
+ "-keepclassmembers class j$.** extends java.io.Serializable { void <init>(); private static final java.io.ObjectStreamField[] serialPersistentFields; static final long serialVersionUID; java.lang.Object readResolve(); java.lang.Object writeReplace(); private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }",
- "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); private static final java.io.ObjectStreamField[] serialPersistentFields; private static final long serialVersionUID;}",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$CounterCell { long value; }",
"-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); public static final !synthetic <fields>; }",
"-keeppackagenames j$.**",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_path.json b/src/library_desugar/jdk11/desugar_jdk_libs_path.json
index c09fa82..7b767e1 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_path.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_path.json
@@ -452,9 +452,9 @@
}
],
"shrinker_config": [
+ "-keepclassmembers class j$.** extends java.io.Serializable { void <init>(); private static final java.io.ObjectStreamField[] serialPersistentFields; static final long serialVersionUID; java.lang.Object readResolve(); java.lang.Object writeReplace(); private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }",
- "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); private static final java.io.ObjectStreamField[] serialPersistentFields; private static final long serialVersionUID;}",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$CounterCell { long value; }",
"-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); public static final !synthetic <fields>; }",
"-keeppackagenames java.**",
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_path_alternative_3.json b/src/library_desugar/jdk11/desugar_jdk_libs_path_alternative_3.json
index 5064ba5..a784fd1 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_path_alternative_3.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_path_alternative_3.json
@@ -318,9 +318,9 @@
}
],
"shrinker_config": [
+ "-keepclassmembers class j$.** extends java.io.Serializable { void <init>(); private static final java.io.ObjectStreamField[] serialPersistentFields; static final long serialVersionUID; java.lang.Object readResolve(); java.lang.Object writeReplace(); private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$TreeBin { int lockState; }",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { int sizeCtl; int transferIndex; long baseCount; int cellsBusy; }",
- "-keepclassmembers class j$.util.concurrent.ConcurrentHashMap { private void readObject(java.io.ObjectInputStream); private void writeObject(java.io.ObjectOutputStream); private void readObjectNoData(); private static final java.io.ObjectStreamField[] serialPersistentFields; private static final long serialVersionUID;}",
"-keepclassmembers class j$.util.concurrent.ConcurrentHashMap$CounterCell { long value; }",
"-keepclassmembers enum * { public static **[] values(); public static ** valueOf(java.lang.String); public static final !synthetic <fields>; }",
"-keeppackagenames j$.**",
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 2145f96..223fc66 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -774,6 +774,13 @@
timing.end();
}
+ if (!options.isMinifying()
+ && appView.options().testing.enableRecordModeling
+ && appView.appInfo().app().getFlags().hasReadRecordReferenceFromProgramClass()) {
+ new Minifier(appView.withLiveness())
+ .replaceDexItemBasedConstString(executorService, timing);
+ }
+
assert verifyMovedMethodsHaveOriginalMethodPosition(appView, getDirectApp(appView));
// If a method filter is present don't produce output since the application is likely partial.
diff --git a/src/main/java/com/android/tools/r8/cf/CfVersion.java b/src/main/java/com/android/tools/r8/cf/CfVersion.java
index 9ce8c64..df6ee75 100644
--- a/src/main/java/com/android/tools/r8/cf/CfVersion.java
+++ b/src/main/java/com/android/tools/r8/cf/CfVersion.java
@@ -40,6 +40,8 @@
public static final CfVersion V17_PREVIEW = new CfVersion(Opcodes.V17 | Opcodes.V_PREVIEW);
public static final CfVersion V18 = new CfVersion(Opcodes.V18);
public static final CfVersion V18_PREVIEW = new CfVersion(Opcodes.V18 | Opcodes.V_PREVIEW);
+ public static final CfVersion V19 = new CfVersion(Opcodes.V19);
+ public static final CfVersion V19_PREVIEW = new CfVersion(Opcodes.V19 | Opcodes.V_PREVIEW);
private final int version;
@@ -61,7 +63,8 @@
CfVersion.V15,
CfVersion.V16,
CfVersion.V17,
- CfVersion.V18
+ CfVersion.V18,
+ CfVersion.V19
};
// Private constructor in case we want to canonicalize versions.
@@ -93,6 +96,10 @@
spec.withInt(CfVersion::major).withInt(CfVersion::minor);
}
+ public static Iterable<CfVersion> all() {
+ return rangeInclusive(versions[0], versions[versions.length - 1]);
+ }
+
public static Iterable<CfVersion> rangeInclusive(CfVersion from, CfVersion to) {
assert from.isLessThanOrEqualTo(to);
assert !from.isPreview() : "This method does not handle preview versions";
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index f669406..8b8b9d8 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -530,9 +530,6 @@
}
private void checkRecord() {
- if (!application.options.shouldDesugarRecords()) {
- return;
- }
if (!accessFlags.isRecord()) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
index b2d2531..4867829 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxerImpl.java
@@ -378,7 +378,7 @@
private void analyzeFieldInstruction(
FieldInstruction fieldInstruction, Set<DexType> eligibleEnums, ProgramMethod context) {
DexField field = fieldInstruction.getField();
- DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(field.holder);
+ DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(field.getHolderType());
if (enumClass != null) {
FieldResolutionResult resolutionResult = appView.appInfo().resolveField(field, context);
if (resolutionResult.isSingleFieldResolutionResult()) {
@@ -552,14 +552,15 @@
}
}
} else if (use.isFieldPut()) {
- DexType type = use.asFieldInstruction().getField().type;
- if (enumUnboxingCandidatesInfo.isCandidate(type)) {
- eligibleEnums.add(type);
+ DexProgramClass enumClass =
+ getEnumUnboxingCandidateOrNull(use.asFieldInstruction().getField().getType());
+ if (enumClass != null) {
+ eligibleEnums.add(enumClass.getType());
}
} else if (use.isReturn()) {
- DexType returnType = code.method().getReference().proto.returnType;
- if (enumUnboxingCandidatesInfo.isCandidate(returnType)) {
- eligibleEnums.add(returnType);
+ DexProgramClass enumClass = getEnumUnboxingCandidateOrNull(code.context().getReturnType());
+ if (enumClass != null) {
+ eligibleEnums.add(enumClass.getType());
}
}
}
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java b/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
index ada07f6..0da73cf 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierMinifier.java
@@ -132,8 +132,7 @@
: appView.dexItemFactory().createString(descriptorToJavaType(rewrittenString.toString()));
}
- private void replaceDexItemBasedConstString(ExecutorService executorService)
- throws ExecutionException {
+ void replaceDexItemBasedConstString(ExecutorService executorService) throws ExecutionException {
ThreadUtils.processItems(
appView.appInfo().classes(),
clazz -> {
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index 2177ea3..ef6142f 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -91,6 +91,14 @@
return lens;
}
+ public void replaceDexItemBasedConstString(ExecutorService executorService, Timing timing)
+ throws ExecutionException {
+ timing.begin("ReplaceDexItemBasedConstString");
+ new IdentifierMinifier(appView, NamingLens.getIdentityLens())
+ .replaceDexItemBasedConstString(executorService);
+ timing.end();
+ }
+
private List<DexClass> computeReachableInterfacesWithDeterministicOrder(
SubtypingInfo subtypingInfo) {
List<DexClass> interfaces = new ArrayList<>();
diff --git a/src/main/java/com/android/tools/r8/retrace/StringRetrace.java b/src/main/java/com/android/tools/r8/retrace/StringRetrace.java
index 1c1a2ee..09f30ca 100644
--- a/src/main/java/com/android/tools/r8/retrace/StringRetrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/StringRetrace.java
@@ -18,6 +18,7 @@
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
+import java.util.function.Supplier;
/**
* Specialized Retrace class for retracing string retraces, with special handling for appending
@@ -169,6 +170,22 @@
return ResultWithContextImpl.create(result, listResultWithContext.getContext());
}
+ /**
+ * Processes supplied strings and calls lineConsumer with retraced strings in a streaming way
+ *
+ * @param lineSupplier the supplier of strings with returning null as terminator
+ * @param lineConsumer the consumer of retraced strings
+ */
+ public void retrace(Supplier<String> lineSupplier, Consumer<String> lineConsumer) {
+ RetraceStackTraceContext context = RetraceStackTraceContext.empty();
+ String retraceLine;
+ while ((retraceLine = lineSupplier.get()) != null) {
+ ResultWithContext<List<String>> result = retrace(retraceLine, context);
+ context = result.getContext();
+ result.getResult().forEach(lineConsumer);
+ }
+ }
+
private void joinAmbiguousLines(
List<List<String>> retracedResult, Consumer<String> joinedConsumer) {
if (retracedResult.isEmpty()) {
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index e74dfd9..2612127 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -143,7 +143,7 @@
}
}
- public static final CfVersion SUPPORTED_CF_VERSION = CfVersion.V17;
+ public static final CfVersion SUPPORTED_CF_VERSION = CfVersion.V19;
public static final int SUPPORTED_DEX_VERSION =
AndroidApiLevel.LATEST.getDexVersion().getIntValue();
@@ -1870,7 +1870,8 @@
public boolean allowInvokeErrors = false;
public boolean allowUnnecessaryDontWarnWildcards = true;
public boolean allowUnusedDontWarnRules = true;
- public boolean reportUnusedProguardConfigurationRules = false;
+ public boolean reportUnusedProguardConfigurationRules =
+ System.getProperty("com.android.tools.r8.reportUnusedProguardConfigurationRules") != null;
public boolean alwaysUseExistingAccessInfoCollectionsInMemberRebinding = true;
public boolean alwaysUsePessimisticRegisterAllocation = false;
public boolean enableCheckCastAndInstanceOfRemoval = true;
@@ -1878,7 +1879,8 @@
public boolean enableInvokeSuperToInvokeVirtualRewriting = true;
public boolean enableMultiANewArrayDesugaringForClassFiles = false;
public boolean enableSwitchToIfRewriting = true;
- public boolean enableEnumUnboxingDebugLogs = false;
+ public boolean enableEnumUnboxingDebugLogs =
+ System.getProperty("com.android.tools.r8.enableEnumUnboxingDebugLogs") != null;
public boolean forceRedundantConstNumberRemoval = false;
public boolean enableExperimentalDesugaredLibraryKeepRuleGenerator = false;
public boolean invertConditionals = false;
diff --git a/src/test/java/com/android/tools/r8/FailCompilationOnFutureVersionsTest.java b/src/test/java/com/android/tools/r8/FailCompilationOnFutureVersionsTest.java
index c71ca8b..f7be6ca 100644
--- a/src/test/java/com/android/tools/r8/FailCompilationOnFutureVersionsTest.java
+++ b/src/test/java/com/android/tools/r8/FailCompilationOnFutureVersionsTest.java
@@ -79,14 +79,15 @@
diagnotics.assertErrorsCount(1);
assertThat(
diagnotics.getErrors().get(0).getDiagnosticMessage(),
- containsString("Unsupported class file version: " + UNSUPPORTED_CF_VERSION));
+ containsString(
+ "Unsupported class file major version " + UNSUPPORTED_CF_VERSION));
assertTrue(
diagnotics.getErrors().stream()
.allMatch(
s ->
s.getDiagnosticMessage()
.toLowerCase()
- .contains("unsupported class file version")));
+ .contains("unsupported class file major version")));
});
} catch (CompilationFailedException e) {
return;
diff --git a/src/test/java/com/android/tools/r8/SupportedClassFileVersions.java b/src/test/java/com/android/tools/r8/SupportedClassFileVersions.java
new file mode 100644
index 0000000..2d6e5b2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/SupportedClassFileVersions.java
@@ -0,0 +1,92 @@
+// 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;
+
+import com.android.tools.r8.cf.CfVersion;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+@RunWith(Parameterized.class)
+public class SupportedClassFileVersions extends TestBase implements Opcodes {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameter(1)
+ public CfVersion version;
+
+ @Parameters(name = "{0}, CF version = {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(), CfVersion.all());
+ }
+
+ @Test
+ public void testDesugar() throws Exception {
+ testForDesugaring(parameters)
+ .addProgramClassFileData(dump(version))
+ .run(parameters.getRuntime(), "Test")
+ .applyIf(
+ c ->
+ DesugarTestConfiguration.isNotDesugared(c) // This implies CF runtime.
+ && version.major() > parameters.asCfRuntime().getVm().getClassfileVersion(),
+ r -> r.assertFailureWithErrorThatThrows(UnsupportedClassVersionError.class),
+ r -> r.assertSuccessWithOutputLines("Hello, world!"));
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClassFileData(dump(version))
+ .addKeepMainRule("Test")
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), "Test")
+ .applyIf(
+ parameters.isCfRuntime()
+ && version.major() > parameters.asCfRuntime().getVm().getClassfileVersion(),
+ r -> r.assertFailureWithErrorThatThrows(UnsupportedClassVersionError.class),
+ r -> r.assertSuccessWithOutputLines("Hello, world!"));
+ }
+
+ public static byte[] dump(CfVersion version) {
+ // Generate a class file with a version higher than the supported one.
+ ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES);
+ MethodVisitor methodVisitor;
+ classWriter.visit(
+ version.raw(), ACC_PUBLIC + ACC_SUPER, "Test", null, "java/lang/Object", null);
+ {
+ methodVisitor = classWriter.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(1, 1);
+ methodVisitor.visitEnd();
+ }
+
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_STATIC, "main", "([Ljava/lang/String;)V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+ methodVisitor.visitLdcInsn("Hello, world!");
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL, "java/io/PrintStream", "println", "(Ljava/lang/Object;)V", false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(2, 1);
+ methodVisitor.visitEnd();
+ }
+ classWriter.visitEnd();
+ return classWriter.toByteArray();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/ValidateInputWithAsmTest.java b/src/test/java/com/android/tools/r8/cf/ValidateInputWithAsmTest.java
new file mode 100644
index 0000000..e0ffc56
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/ValidateInputWithAsmTest.java
@@ -0,0 +1,89 @@
+// 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;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static org.hamcrest.CoreMatchers.containsString;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestCompilerBuilder;
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.transformers.MethodTransformer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ValidateInputWithAsmTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ @Test(expected = CompilationFailedException.class)
+ public void testD8() throws Exception {
+ testForD8(Backend.DEX)
+ .apply(this::configure)
+ .compileWithExpectedDiagnostics(this::checkDiagnostics);
+ }
+
+ @Test(expected = CompilationFailedException.class)
+ public void testR8() throws Exception {
+ testForR8(Backend.DEX)
+ .apply(this::configure)
+ .addKeepMainRule(TestClass.class)
+ .compileWithExpectedDiagnostics(this::checkDiagnostics);
+ }
+
+ private void configure(TestCompilerBuilder<?, ?, ?, ?, ?> builder) throws Exception {
+ builder
+ .addProgramClassFileData(getInvalidClass())
+ .setMinApi(AndroidApiLevel.B)
+ .addOptionsModification(options -> options.testing.verifyInputs = true);
+ }
+
+ private void checkDiagnostics(TestDiagnosticMessages diagnostics) {
+ diagnostics
+ .assertOnlyErrors()
+ .assertAllErrorsMatch(
+ diagnosticMessage(containsString("INVOKEVIRTUAL can't be used with interfaces")));
+ }
+
+ private byte[] getInvalidClass() throws Exception {
+ return transformer(TestClass.class)
+ .addMethodTransformer(
+ new MethodTransformer() {
+ @Override
+ public void visitMethodInsn(
+ final int opcode,
+ final String owner,
+ final String name,
+ final String descriptor,
+ final boolean isInterface) {
+ if (owner.endsWith("PrintStream")) {
+ super.visitMethodInsn(opcode, owner, name, descriptor, true);
+ } else {
+ super.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+ }
+ })
+ .transform();
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ System.out.println("Hello, world!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
index 41c05a3..f411d91 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/InvalidStackHeightTest.java
@@ -5,8 +5,6 @@
package com.android.tools.r8.cf.stackmap;
import static org.hamcrest.CoreMatchers.containsString;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationFailedException;
@@ -81,23 +79,6 @@
containsString("The max stack height of 1 is violated"));
}
- @Test()
- public void testR8InputVerification() throws Exception {
- try {
- testForR8(parameters.getBackend())
- .addProgramClassFileData(getMainWithChangedMaxStackHeight())
- .enableInliningAnnotations()
- .addKeepMainRule(Main.class)
- .setMinApi(parameters.getApiLevel())
- .addOptionsModification(options -> options.testing.verifyInputs = true)
- .compile();
- } catch (CompilationFailedException e) {
- assertTrue(e.getCause().getMessage().contains("Insufficient maximum stack size"));
- return;
- }
- fail("Should always throw");
- }
-
public byte[] getMainWithChangedMaxStackHeight() throws Exception {
return transformer(Main.class).setMaxStackHeight(MethodPredicate.onName("main"), 1).transform();
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java
index 3afc61c..1009f56 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/ConcurrentHashMapFileSerializationTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.desugar.desugaredlibrary.gson;
+import static com.android.tools.r8.desugar.desugaredlibrary.gson.GsonDesugaredLibraryTestUtils.uniqueName;
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static org.junit.Assert.assertFalse;
@@ -72,7 +73,10 @@
.compile()
.inspectL8(this::assertVersionUID)
.withArt6Plus64BitsLib()
- .run(parameters.getRuntime(), Executor.class)
+ .run(
+ parameters.getRuntime(),
+ Executor.class,
+ uniqueName(temp, libraryDesugaringSpecification, compilationSpecification, parameters))
.assertSuccessWithOutput(EXPECTED_RESULT);
}
@@ -90,15 +94,15 @@
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
static class Executor {
public static void main(String[] args) throws Exception {
- chmTest();
+ chmTest(args[0]);
}
@SuppressWarnings("unchecked")
- private static void chmTest() throws IOException, ClassNotFoundException {
+ private static void chmTest(String uniqueName) throws IOException, ClassNotFoundException {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>();
map.put("k1", "v1");
map.put("k2", "v2");
- File file = new File("testTemp");
+ File file = new File(uniqueName);
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonAllMapsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonAllMapsTest.java
index e7421fe..c861001 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonAllMapsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonAllMapsTest.java
@@ -3,10 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.desugar.desugaredlibrary.gson;
+import static com.android.tools.r8.desugar.desugaredlibrary.gson.GsonDesugaredLibraryTestUtils.GSON_2_8_1_JAR;
+import static com.android.tools.r8.desugar.desugaredlibrary.gson.GsonDesugaredLibraryTestUtils.GSON_CONFIGURATION;
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import java.util.List;
@@ -17,7 +20,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class GsonAllMapsTest extends GsonDesugaredLibraryTestBase {
+public class GsonAllMapsTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
private final LibraryDesugaringSpecification libraryDesugaringSpecification;
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonDesugaredLibraryTestBase.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonDesugaredLibraryTestBase.java
deleted file mode 100644
index 1904ff7..0000000
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonDesugaredLibraryTestBase.java
+++ /dev/null
@@ -1,14 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.desugar.desugaredlibrary.gson;
-
-import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-
-public abstract class GsonDesugaredLibraryTestBase extends DesugaredLibraryTestBase {
- protected static final Path GSON_CONFIGURATION =
- Paths.get("src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/gson.cfg");
- protected static final Path GSON_2_8_1_JAR = Paths.get("third_party/iosched_2019/gson-2.8.1.jar");
-}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonDesugaredLibraryTestUtils.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonDesugaredLibraryTestUtils.java
new file mode 100644
index 0000000..b07f7b9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonDesugaredLibraryTestUtils.java
@@ -0,0 +1,36 @@
+// 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.desugar.desugaredlibrary.gson;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import org.junit.rules.TemporaryFolder;
+
+public abstract class GsonDesugaredLibraryTestUtils {
+
+ static final Path GSON_CONFIGURATION =
+ Paths.get("src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/gson.cfg");
+ static final Path GSON_2_8_1_JAR = Paths.get("third_party/iosched_2019/gson-2.8.1.jar");
+
+ static String uniqueName(
+ TemporaryFolder temp,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification,
+ TestParameters parameters)
+ throws IOException {
+ return temp.newFolder("test_serialization").toString()
+ + "/test_"
+ + libraryDesugaringSpecification.toString()
+ + "_"
+ + compilationSpecification.toString()
+ + "_"
+ + parameters.getRuntime()
+ + "_"
+ + parameters.getApiLevel();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonOptionalTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonOptionalTest.java
index d42473c..d1a5a9e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonOptionalTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/GsonOptionalTest.java
@@ -3,10 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.desugar.desugaredlibrary.gson;
+import static com.android.tools.r8.desugar.desugaredlibrary.gson.GsonDesugaredLibraryTestUtils.GSON_2_8_1_JAR;
+import static com.android.tools.r8.desugar.desugaredlibrary.gson.GsonDesugaredLibraryTestUtils.GSON_CONFIGURATION;
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.utils.StringUtils;
@@ -18,7 +21,7 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class GsonOptionalTest extends GsonDesugaredLibraryTestBase {
+public class GsonOptionalTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
private final LibraryDesugaringSpecification libraryDesugaringSpecification;
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/MyMapFileSerializationTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/MyMapFileSerializationTest.java
index 3c85888..2387d64 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/MyMapFileSerializationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/MyMapFileSerializationTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.desugar.desugaredlibrary.gson;
+import static com.android.tools.r8.desugar.desugaredlibrary.gson.GsonDesugaredLibraryTestUtils.uniqueName;
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
@@ -64,20 +65,13 @@
.noMinification()
.compile()
.withArt6Plus64BitsLib()
- .run(parameters.getRuntime(), Executor.class, uniqueName())
+ .run(
+ parameters.getRuntime(),
+ Executor.class,
+ uniqueName(temp, libraryDesugaringSpecification, compilationSpecification, parameters))
.assertSuccessWithOutput(EXPECTED_RESULT);
}
- private String uniqueName() {
- return libraryDesugaringSpecification.toString()
- + "_"
- + compilationSpecification.toString()
- + "_"
- + parameters.getRuntime()
- + "_"
- + parameters.getApiLevel();
- }
-
@SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
static class Executor {
@@ -86,10 +80,7 @@
MyMap<String, String> map = new MyMap<>();
map.put("k1", "v1");
map.put("k2", "v2");
- // It seems the FileSystem is shared across multiple VM runs at least on some VMs.
- // There is no easy way to create a temp file that works on all VM/configurations.
- // We pass a unique string as parameter that we use for the file name.
- File file = new File("test_" + args[0]);
+ File file = new File(args[0]);
FileOutputStream fos = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fos);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/TimeSerializationTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/TimeSerializationTest.java
new file mode 100644
index 0000000..5c87fb9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/gson/TimeSerializationTest.java
@@ -0,0 +1,117 @@
+// 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.desugar.desugaredlibrary.gson;
+
+import static com.android.tools.r8.desugar.desugaredlibrary.gson.GsonDesugaredLibraryTestUtils.uniqueName;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.time.ZoneId;
+import java.time.ZoneOffset;
+import java.time.ZonedDateTime;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class TimeSerializationTest extends DesugaredLibraryTestBase {
+
+ private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
+
+ private static final String EXPECTED_RESULT =
+ StringUtils.lines(
+ "Z",
+ "GMT",
+ "2008-06-01T20:30:42.000000111Z[GMT]",
+ "Z",
+ "GMT",
+ "2008-06-01T20:30:42.000000111Z[GMT]");
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ // TODO(b/134732760): Skip Android 4.4.4 due to missing libjavacrypto.
+ getTestParameters()
+ .withDexRuntime(Version.V4_0_4)
+ .withDexRuntimesStartingFromIncluding(Version.V5_1_1)
+ .withAllApiLevels()
+ .build(),
+ getJdk8Jdk11(),
+ DEFAULT_SPECIFICATIONS);
+ }
+
+ public TimeSerializationTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
+ this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
+ }
+
+ @Test
+ public void testZonedDateTimeSerialization() throws Throwable {
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(TimeSerializationTest.class)
+ .addKeepMainRule(Executor.class)
+ .compile()
+ .withArt6Plus64BitsLib()
+ .run(
+ parameters.getRuntime(),
+ Executor.class,
+ uniqueName(temp, libraryDesugaringSpecification, compilationSpecification, parameters))
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ @SuppressWarnings("MismatchedQueryAndUpdateOfCollection")
+ static class Executor {
+
+ @SuppressWarnings("unchecked")
+ public static void main(String[] args) throws Exception {
+ ZoneOffset offset = ZoneOffset.UTC;
+ System.out.println(offset);
+ ZoneId gmt = ZoneId.of("GMT");
+ System.out.println(gmt);
+ ZonedDateTime dateTime = ZonedDateTime.of(2008, 6, 1, 20, 30, 42, 111, gmt);
+ System.out.println(dateTime);
+ File file = new File(args[0]);
+
+ FileOutputStream fos = new FileOutputStream(file);
+ ObjectOutputStream oos = new ObjectOutputStream(fos);
+ oos.writeObject(offset);
+ oos.writeObject(gmt);
+ oos.writeObject(dateTime);
+ oos.close();
+ fos.close();
+
+ FileInputStream fis = new FileInputStream(file);
+ ObjectInputStream ois = new ObjectInputStream(fis);
+ ZoneOffset newOffset = (ZoneOffset) ois.readObject();
+ ZoneId newGmt = (ZoneId) ois.readObject();
+ ZonedDateTime newDateTime = (ZonedDateTime) ois.readObject();
+ fis.close();
+ ois.close();
+
+ System.out.println(newOffset);
+ System.out.println(newGmt);
+ System.out.println(newDateTime);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
index 2554cf0..75dc0c4 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.AssertUtils;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -66,28 +65,22 @@
@Test
public void testR8() throws Exception {
- // TODO(b/233857841): Should always succeed.
- AssertUtils.assertFailsCompilationIf(
- parameters.isDexRuntime() && !enableMinification,
- () ->
- testForR8(parameters.getBackend())
- .addProgramClassFileData(PROGRAM_DATA)
- .addKeepMainRule(MAIN_TYPE)
- .applyIf(
- parameters.isCfRuntime(),
- testBuilder ->
- testBuilder.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp)))
- .minification(enableMinification)
- .setMinApi(parameters.getApiLevel())
- .compile()
- .applyIf(
- parameters.isCfRuntime(),
- compileResult ->
- compileResult.inspect(RecordTestUtils::assertRecordsAreRecords))
- .run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(
- enableMinification
- ? EXPECTED_RESULT_R8_MINIFICATION
- : EXPECTED_RESULT_R8_NO_MINIFICATION));
+ testForR8(parameters.getBackend())
+ .addProgramClassFileData(PROGRAM_DATA)
+ .addKeepMainRule(MAIN_TYPE)
+ .applyIf(
+ parameters.isCfRuntime(),
+ testBuilder -> testBuilder.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp)))
+ .minification(enableMinification)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .applyIf(
+ parameters.isCfRuntime(),
+ compileResult -> compileResult.inspect(RecordTestUtils::assertRecordsAreRecords))
+ .run(parameters.getRuntime(), MAIN_TYPE)
+ .assertSuccessWithOutput(
+ enableMinification
+ ? EXPECTED_RESULT_R8_MINIFICATION
+ : EXPECTED_RESULT_R8_NO_MINIFICATION);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordShrinkFieldTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordShrinkFieldTest.java
index 2c426fc..a8073f5 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordShrinkFieldTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordShrinkFieldTest.java
@@ -8,11 +8,13 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.nio.file.Path;
import java.util.List;
+import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -23,26 +25,33 @@
private static final String RECORD_NAME = "RecordShrinkField";
private static final byte[][] PROGRAM_DATA = RecordTestUtils.getProgramData(RECORD_NAME);
private static final String MAIN_TYPE = RecordTestUtils.getMainType(RECORD_NAME);
- private static final String EXPECTED_RESULT =
- StringUtils.lines("%s[unused=-1, name=Jane Doe, age=42]", "%s[unused=-1, name=Bob, age=42]");
+
private static final String EXPECTED_RESULT_D8 =
- String.format(EXPECTED_RESULT, "Person", "Person");
+ StringUtils.lines(
+ "Person[unused=-1, name=Jane Doe, age=42]", "Person[unused=-1, name=Bob, age=42]");
private static final String EXPECTED_RESULT_R8 = StringUtils.lines("a[a=Jane Doe]", "a[a=Bob]");
+ private static final String EXPECTED_RESULT_R8_NO_MINIFICATION =
+ StringUtils.lines(
+ "RecordShrinkField$Person[name=Jane Doe]", "RecordShrinkField$Person[name=Bob]");
private final TestParameters parameters;
+ private final boolean minifying;
- public RecordShrinkFieldTest(TestParameters parameters) {
+ public RecordShrinkFieldTest(TestParameters parameters, boolean minifying) {
this.parameters = parameters;
+ this.minifying = minifying;
}
- @Parameterized.Parameters(name = "{0}")
+ @Parameterized.Parameters(name = "{0}, minifying: {1}")
public static List<Object[]> data() {
return buildParameters(
- getTestParameters().withDexRuntimes().withAllApiLevelsAlsoForCf().build());
+ getTestParameters().withDexRuntimes().withAllApiLevelsAlsoForCf().build(),
+ BooleanUtils.values());
}
@Test
public void testD8() throws Exception {
+ Assume.assumeTrue("Only valid in R8", minifying);
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
@@ -57,10 +66,12 @@
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_TYPE)
+ .minification(minifying)
.compile()
.inspect(this::assertSingleField)
.run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT_R8);
+ .assertSuccessWithOutput(
+ minifying ? EXPECTED_RESULT_R8 : EXPECTED_RESULT_R8_NO_MINIFICATION);
}
@Test
@@ -70,6 +81,7 @@
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_TYPE)
+ .minification(minifying)
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
.compile()
.writeToZip();
@@ -77,14 +89,17 @@
.addProgramFiles(desugared)
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_TYPE)
+ .minification(minifying)
.compile()
.inspect(this::assertSingleField)
.run(parameters.getRuntime(), MAIN_TYPE)
- .assertSuccessWithOutput(EXPECTED_RESULT_R8);
+ .assertSuccessWithOutput(
+ minifying ? EXPECTED_RESULT_R8 : EXPECTED_RESULT_R8_NO_MINIFICATION);
}
private void assertSingleField(CodeInspector inspector) {
- ClassSubject recordClass = inspector.clazz("records.a");
+ ClassSubject recordClass =
+ inspector.clazz(minifying ? "records.a" : "records.RecordShrinkField$Person");
assertEquals(1, recordClass.allInstanceFields().size());
assertEquals(
"java.lang.String", recordClass.allInstanceFields().get(0).getField().type().toString());
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/NullAssignmentToArrayTypeEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/NullAssignmentToArrayTypeEnumUnboxingTest.java
new file mode 100644
index 0000000..947121d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/NullAssignmentToArrayTypeEnumUnboxingTest.java
@@ -0,0 +1,97 @@
+// 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.enumunboxing;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
+import org.junit.runners.Parameterized.Parameters;
+
+/** Regression test for b/236618700. */
+@RunWith(Parameterized.class)
+public class NullAssignmentToArrayTypeEnumUnboxingTest extends EnumUnboxingTestBase {
+
+ @Parameter(0)
+ public TestParameters parameters;
+
+ @Parameter(1)
+ public boolean enumValueOptimization;
+
+ @Parameter(2)
+ public EnumKeepRules enumKeepRules;
+
+ @Parameters(name = "{0}, value opt.: {1}, keep: {2}")
+ public static List<Object[]> data() {
+ return enumUnboxingTestParameters();
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(NullAssignmentToArrayTypeEnumUnboxingTest.class)
+ .addKeepMainRule(Main.class)
+ .addKeepRules(enumKeepRules.getKeepRules())
+ .addEnumUnboxingInspector(inspector -> inspector.assertUnboxed(MyEnum.class))
+ .enableInliningAnnotations()
+ .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject mainClassSubject = inspector.clazz(Main.class);
+ assertThat(mainClassSubject, isPresent());
+
+ MethodSubject clinitMethodSubject = mainClassSubject.clinit();
+ assertThat(clinitMethodSubject, isPresent());
+ assertTrue(
+ clinitMethodSubject
+ .streamInstructions()
+ .anyMatch(InstructionSubject::isFieldAccess));
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ static class Main {
+
+ static MyEnum[] e;
+
+ static {
+ System.currentTimeMillis(); // To preserve the null assignment below.
+ e = null;
+ }
+
+ public static void main(String[] args) {
+ setField();
+ getField();
+ }
+
+ @NeverInline
+ static void setField() {
+ e = new MyEnum[] {System.currentTimeMillis() > 0 ? MyEnum.A : MyEnum.B};
+ }
+
+ @NeverInline
+ static void getField() {
+ System.out.println(e[0].name());
+ }
+ }
+
+ enum MyEnum {
+ A,
+ B
+ }
+}
diff --git a/tools/asmifier.py b/tools/asmifier.py
index 2b6a799..ae7d1e6 100755
--- a/tools/asmifier.py
+++ b/tools/asmifier.py
@@ -10,7 +10,7 @@
import sys
import utils
-ASM_VERSION = '9.2'
+ASM_VERSION = '9.3'
ASM_JAR = 'asm-' + ASM_VERSION + '.jar'
ASM_UTIL_JAR = 'asm-util-' + ASM_VERSION + '.jar'