Merge commit 'c933a05659b0b0808dbf898636b6ef6a9319e55c' into dev-release
diff --git a/build.gradle b/build.gradle
index 9981676..21a20be 100644
--- a/build.gradle
+++ b/build.gradle
@@ -779,11 +779,16 @@
archiveFileName = 'sources_main_11.jar'
}
-def r8CreateTask(name, baseName, sources, includeSwissArmyKnife) {
+def r8CreateTask(name, baseName, sources, includeLibraryLicenses, includeSwissArmyKnife) {
return tasks.create("r8Create${name}", Jar) {
entryCompression ZipEntryCompression.STORED
dependsOn sources
- from consolidatedLicense.outputs.files
+ dependsOn files('LICENSE')
+ if (includeLibraryLicenses) {
+ from consolidatedLicense.outputs.files
+ } else {
+ from files('LICENSE')
+ }
from sources.collect { zipTree(it) }
exclude "$buildDir/classes/**"
archiveFileName = baseName
@@ -844,6 +849,7 @@
'WithDeps',
'r8_with_deps.jar',
repackageSources.outputs.files + repackageDeps.outputs.files,
+ true,
true)
dependsOn r8Task
outputs.files r8Task.outputs.files
@@ -857,6 +863,7 @@
'WithDeps11',
'r8_with_deps_11.jar',
repackageSources11.outputs.files + repackageDeps.outputs.files,
+ true,
true)
dependsOn r8Task
outputs.files r8Task.outputs.files
@@ -883,6 +890,7 @@
'WithoutDeps',
'r8_without_deps.jar',
repackageSources.outputs.files,
+ false,
true)
dependsOn r8Task
outputs.files r8Task.outputs.files
@@ -905,6 +913,7 @@
'NoManifestWithoutDeps',
'r8_no_manifest_without_deps.jar',
repackageSources.outputs.files,
+ false,
false)
dependsOn r8Task
outputs.files r8Task.outputs.files
@@ -917,6 +926,7 @@
'NoManifestWithDeps',
'r8_no_manifest_with_deps.jar',
repackageSources.outputs.files + repackageDeps.outputs.files,
+ true,
false)
dependsOn r8Task
outputs.files r8Task.outputs.files
diff --git a/scripts/dex-size-in-apk.sh b/scripts/dex-size-in-apk.sh
new file mode 100755
index 0000000..ebc9364
--- /dev/null
+++ b/scripts/dex-size-in-apk.sh
@@ -0,0 +1,7 @@
+#!/bin/bash
+#
+# 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.
+
+zipinfo $1 | grep 'classes.*\.dex' | awk '{printf "%s%s",sep,$4; sep="+"} END{print ""}' | bc
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index 27bdafd..9dc5143 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -48,6 +48,7 @@
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.Timing;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.io.File;
import java.io.PrintStream;
@@ -56,6 +57,7 @@
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashMap;
@@ -75,22 +77,39 @@
private final InternalOptions options = new InternalOptions(factory, reporter);
private final MachineDesugaredLibrarySpecification desugaredLibrarySpecification;
- private final Path desugaredLibraryImplementation;
+ private final Collection<Path> desugaredLibraryImplementation;
private final Path outputDirectory;
private final Set<DexMethod> parallelMethods = Sets.newIdentityHashSet();
+ public static GenerateLintFiles createForTesting(
+ Path specification, Set<Path> implementation, Path outputDirectory) throws Exception {
+ return new GenerateLintFiles(specification, implementation, outputDirectory);
+ }
+
public GenerateLintFiles(
String desugarConfigurationPath, String desugarImplementationPath, String outputDirectory)
throws Exception {
+ this(
+ Paths.get(desugarConfigurationPath),
+ ImmutableList.of(Paths.get(desugarImplementationPath)),
+ Paths.get(outputDirectory));
+ }
+
+ private GenerateLintFiles(
+ Path desugarConfigurationPath,
+ Collection<Path> desugarImplementationPath,
+ Path outputDirectory)
+ throws Exception {
DesugaredLibrarySpecification specification =
readDesugaredLibraryConfiguration(desugarConfigurationPath);
Path androidJarPath = getAndroidJarPath(specification.getRequiredCompilationApiLevel());
this.desugaredLibrarySpecification =
- specification.toMachineSpecification(options, androidJarPath, Timing.empty());
+ specification.toMachineSpecification(
+ options, ImmutableList.of(androidJarPath), Timing.empty());
- this.desugaredLibraryImplementation = Paths.get(desugarImplementationPath);
- this.outputDirectory = Paths.get(outputDirectory);
+ this.desugaredLibraryImplementation = desugarImplementationPath;
+ this.outputDirectory = outputDirectory;
if (!Files.isDirectory(this.outputDirectory)) {
throw new Exception("Output directory " + outputDirectory + " is not a directory");
}
@@ -125,9 +144,9 @@
}
private DesugaredLibrarySpecification readDesugaredLibraryConfiguration(
- String desugarConfigurationPath) {
+ Path desugarConfigurationPath) {
return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
- StringResource.fromFile(Paths.get(desugarConfigurationPath)),
+ StringResource.fromFile(desugarConfigurationPath),
factory,
reporter,
false,
diff --git a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
index 9798222..d2c931e 100644
--- a/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfCodePrinter.java
@@ -21,7 +21,6 @@
import com.android.tools.r8.cf.code.CfDexItemBasedConstString;
import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfGoto;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfIfCmp;
@@ -52,6 +51,7 @@
import com.android.tools.r8.cf.code.CfSwitch;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.CfCode;
@@ -201,7 +201,7 @@
}
private String frameTypeType() {
- return r8Type("FrameType", ImmutableList.of("cf", "code", "CfFrame"));
+ return r8Type("FrameType", ImmutableList.of("cf", "code", "frame"));
}
private String monitorType() {
@@ -544,7 +544,7 @@
} else {
return frameTypeType()
+ ".initialized("
- + dexType(frameType.asSingleInitializedType().getInitializedType())
+ + dexType(frameType.asInitializedReferenceType().getInitializedType())
+ ")";
}
}
diff --git a/src/main/java/com/android/tools/r8/cf/CfPrinter.java b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
index 6030119..0c4a184 100644
--- a/src/main/java/com/android/tools/r8/cf/CfPrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.cf.code.CfDexItemBasedConstString;
import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfGoto;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfIfCmp;
@@ -55,6 +54,8 @@
import com.android.tools.r8.cf.code.CfSwitch.Kind;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.cf.code.frame.PreciseFrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCode.LocalVariableInfo;
@@ -445,7 +446,7 @@
builder.append("] [");
{
String separator = "";
- for (FrameType element : frame.getStack()) {
+ for (PreciseFrameType element : frame.getStack()) {
builder.append(separator);
print(element);
separator = ", ";
@@ -458,7 +459,7 @@
if (type.isPrimitive()) {
builder.append(type.asPrimitive().getTypeName());
} else if (type.isInitialized()) {
- appendType(type.asSingleInitializedType().getInitializedType());
+ appendType(type.asInitializedReferenceType().getInitializedType());
} else if (type.isUninitializedNew()) {
builder.append("uninitialized ").append(getLabel(type.getUninitializedLabel()));
} else {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
index 993dd8e..3ed5c3a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -4,13 +4,11 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -207,18 +205,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., value1, value2 →
- // ..., result
- FrameType frameType = FrameType.fromNumericType(type, dexItemFactory);
- frameBuilder.popAndDiscard(frameType, frameType).push(frameType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState state,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
index 8a39916..78b9067 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -82,19 +81,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., arrayref →
- // ..., length
- frameBuilder
- .popAndDiscardInitialized(dexItemFactory.objectArrayType)
- .push(dexItemFactory.intType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index 129219b..8bba186 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -4,13 +4,11 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -128,18 +126,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., arrayref, index →
- // ..., value
- frameBuilder.popAndDiscardInitialized(dexItemFactory.objectArrayType, dexItemFactory.intType);
- frameBuilder.push(FrameType.fromPreciseMemberType(type, dexItemFactory));
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
index 965c413..489285f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -4,13 +4,11 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -119,19 +117,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., arrayref, index, value →
- // ...
- frameBuilder
- .popAndDiscard(FrameType.fromPreciseMemberType(type, dexItemFactory))
- .popAndDiscardInitialized(dexItemFactory.objectArrayType, dexItemFactory.intType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java b/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java
index 8335908..dc247a4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfAssignability.java
@@ -4,7 +4,8 @@
package com.android.tools.r8.cf.code;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.cf.code.frame.PreciseFrameType;
import com.android.tools.r8.cf.code.frame.SingleFrameType;
import com.android.tools.r8.cf.code.frame.WideFrameType;
import com.android.tools.r8.graph.AppView;
@@ -27,7 +28,7 @@
}
return source.isSingle()
? isFrameTypeAssignable(source.asSingle(), target.asSingle(), appView)
- : isFrameTypeAssignable(source.asWide(), target.asWide(), appView);
+ : isFrameTypeAssignable(source.asWide(), target.asWide());
}
// Based on https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1.2.
@@ -61,17 +62,16 @@
if (source.isInitialized()) {
// Both are instantiated types and we resort to primitive type/java type hierarchy checking.
return isAssignable(
- source.asSingleInitializedType().getInitializedType(),
- target.asSingleInitializedType().getInitializedType(),
+ source.asInitializedReferenceType().getInitializedType(),
+ target.asInitializedReferenceType().getInitializedType(),
appView);
}
- return target.asSingleInitializedType().getInitializedType() == factory.objectType;
+ return target.asInitializedReferenceType().getInitializedType() == factory.objectType;
}
return false;
}
- public static boolean isFrameTypeAssignable(
- WideFrameType source, WideFrameType target, AppView<?> appView) {
+ public static boolean isFrameTypeAssignable(WideFrameType source, WideFrameType target) {
assert !source.isTwoWord();
return source.lessThanOrEqualTo(target);
}
@@ -174,7 +174,9 @@
}
public static AssignabilityResult isStackAssignable(
- Deque<FrameType> sourceStack, Deque<FrameType> targetStack, AppView<?> appView) {
+ Deque<PreciseFrameType> sourceStack,
+ Deque<PreciseFrameType> targetStack,
+ AppView<?> appView) {
if (sourceStack.size() != targetStack.size()) {
return new FailedAssignabilityResult(
"Source stack "
@@ -183,14 +185,10 @@
+ Arrays.toString(targetStack.toArray())
+ " is not the same size");
}
- Iterator<FrameType> otherIterator = targetStack.iterator();
+ Iterator<PreciseFrameType> otherIterator = targetStack.iterator();
int stackIndex = 0;
- for (FrameType sourceType : sourceStack) {
- FrameType destinationType = otherIterator.next();
- // TODO(b/231260627): By strengthening the stack to Deque<SpecificFrameType> the following
- // asserts would be trivial as a result of type checking.
- assert sourceType.isSpecific();
- assert destinationType.isSpecific();
+ for (PreciseFrameType sourceType : sourceStack) {
+ PreciseFrameType destinationType = otherIterator.next();
if (!isFrameTypeAssignable(sourceType, destinationType, appView)) {
return new FailedAssignabilityResult(
"Could not assign '"
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
index 6ad249b..8d7fe37 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -133,17 +132,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., objectref →
- // ..., objectref
- frameBuilder.popAndDiscardInitialized(dexItemFactory.objectType).push(type);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
index 5d3f7b9..c9edfea 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
@@ -4,13 +4,11 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -132,18 +130,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., value1, value2 →
- // ..., result
- FrameType frameType = FrameType.fromNumericType(type, dexItemFactory);
- frameBuilder.popAndDiscard(frameType, frameType).push(dexItemFactory.intType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index 43e8eee..b76a1f3 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -140,17 +139,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ... →
- // ..., value
- frameBuilder.push(dexItemFactory.classType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
index da94a6ba..48a6368 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstDynamic.java
@@ -227,17 +227,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ... →
- // ..., value
- frameBuilder.push(dexItemFactory.classType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
index ad9f25e..0932c43 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -104,17 +103,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ... →
- // ..., value
- frameBuilder.push(dexItemFactory.methodHandleType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
index dc1bee0..74131ae 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -102,17 +101,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ... →
- // ..., value
- frameBuilder.push(dexItemFactory.methodTypeType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
index 546fd6b..ed6f4ea 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -74,17 +73,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ... →
- // ..., value
- frameBuilder.push(DexItemFactory.nullValueType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
index 3277d2b..f777da5 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -231,18 +230,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ... →
- // ..., value
- assert type.isPrimitive();
- frameBuilder.push(type.toDexType(dexItemFactory));
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
index e143829..a205cb7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -105,17 +104,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ... →
- // ..., value
- frameBuilder.push(dexItemFactory.stringType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
index 374b722..5dcc3fb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -124,17 +123,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ... →
- // ..., value
- frameBuilder.push(dexItemFactory.stringType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
index fafcb67..8d00469 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -6,23 +6,17 @@
import static org.objectweb.asm.Opcodes.F_NEW;
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.frame.PrimitiveFrameType;
-import com.android.tools.r8.cf.code.frame.SingleFrameType;
-import com.android.tools.r8.cf.code.frame.WideFrameType;
-import com.android.tools.r8.errors.Unimplemented;
-import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.cf.code.frame.PreciseFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.CfCodeStackMapValidatingException;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.code.MemberType;
-import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
@@ -50,282 +44,7 @@
public class CfFrame extends CfInstruction implements Cloneable {
public static final Int2ObjectSortedMap<FrameType> EMPTY_LOCALS = Int2ObjectSortedMaps.emptyMap();
- public static final Deque<FrameType> EMPTY_STACK = ImmutableDeque.of();
-
- public abstract static class FrameType {
-
- public static BooleanFrameType booleanType() {
- return BooleanFrameType.SINGLETON;
- }
-
- public static ByteFrameType byteType() {
- return ByteFrameType.SINGLETON;
- }
-
- public static CharFrameType charType() {
- return CharFrameType.SINGLETON;
- }
-
- public static DoubleFrameType doubleType() {
- return DoubleFrameType.SINGLETON;
- }
-
- public static FloatFrameType floatType() {
- return FloatFrameType.SINGLETON;
- }
-
- public static IntFrameType intType() {
- return IntFrameType.SINGLETON;
- }
-
- public static LongFrameType longType() {
- return LongFrameType.SINGLETON;
- }
-
- public static ShortFrameType shortType() {
- return ShortFrameType.SINGLETON;
- }
-
- public static FrameType initialized(DexType type) {
- if (type.isPrimitiveType()) {
- char c = (char) type.getDescriptor().content[0];
- switch (c) {
- case 'Z':
- return booleanType();
- case 'B':
- return byteType();
- case 'C':
- return charType();
- case 'D':
- return doubleType();
- case 'F':
- return floatType();
- case 'I':
- return intType();
- case 'J':
- return longType();
- case 'S':
- return shortType();
- default:
- throw new Unreachable("Unexpected primitive type: " + type.getTypeName());
- }
- }
- return new SingleInitializedType(type);
- }
-
- public static FrameType uninitializedNew(CfLabel label, DexType typeToInitialize) {
- return new UninitializedNew(label, typeToInitialize);
- }
-
- public static FrameType uninitializedThis() {
- return UninitializedThis.SINGLETON;
- }
-
- public static OneWord oneWord() {
- return OneWord.SINGLETON;
- }
-
- public static TwoWord twoWord() {
- return TwoWord.SINGLETON;
- }
-
- public FrameType asFrameType() {
- return this;
- }
-
- abstract Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens);
-
- public boolean isBoolean() {
- return false;
- }
-
- public boolean isByte() {
- return false;
- }
-
- public boolean isChar() {
- return false;
- }
-
- public boolean isDouble() {
- return false;
- }
-
- public boolean isFloat() {
- return false;
- }
-
- public boolean isInt() {
- return false;
- }
-
- public boolean isLong() {
- return false;
- }
-
- public boolean isShort() {
- return false;
- }
-
- public boolean isNullType() {
- return false;
- }
-
- public boolean isObject() {
- return false;
- }
-
- public DexType getObjectType(DexType context) {
- assert false : "Unexpected use of getObjectType() for non-object FrameType";
- return null;
- }
-
- public boolean isPrimitive() {
- return false;
- }
-
- public PrimitiveFrameType asPrimitive() {
- return null;
- }
-
- public final boolean isSingle() {
- return !isWide();
- }
-
- public SingleFrameType asSingle() {
- return null;
- }
-
- public SinglePrimitiveFrameType asSinglePrimitive() {
- return null;
- }
-
- public SingleInitializedType asSingleInitializedType() {
- return null;
- }
-
- public boolean isWide() {
- return false;
- }
-
- public WideFrameType asWide() {
- return null;
- }
-
- public int getWidth() {
- assert isSingle();
- return 1;
- }
-
- public boolean isUninitializedNew() {
- return false;
- }
-
- public boolean isUninitializedObject() {
- return false;
- }
-
- public CfLabel getUninitializedLabel() {
- return null;
- }
-
- public boolean isUninitializedThis() {
- return false;
- }
-
- public boolean isInitialized() {
- return false;
- }
-
- public DexType getInitializedType(DexItemFactory dexItemFactory) {
- return null;
- }
-
- public DexType getUninitializedNewType() {
- return null;
- }
-
- public boolean isOneWord() {
- return false;
- }
-
- public boolean isSpecific() {
- return true;
- }
-
- public boolean isTwoWord() {
- return false;
- }
-
- FrameType map(java.util.function.Function<DexType, DexType> func) {
- if (isObject()) {
- if (isInitialized()) {
- DexType type = asSingleInitializedType().getInitializedType();
- DexType newType = func.apply(type);
- if (type != newType) {
- return initialized(newType);
- }
- }
- if (isUninitializedNew()) {
- DexType type = getUninitializedNewType();
- DexType newType = func.apply(type);
- if (type != newType) {
- return uninitializedNew(getUninitializedLabel(), newType);
- }
- }
- }
- return this;
- }
-
- private FrameType() {}
-
- @Override
- public abstract boolean equals(Object obj);
-
- @Override
- public abstract int hashCode();
-
- public static FrameType fromPreciseMemberType(MemberType memberType, DexItemFactory factory) {
- assert memberType.isPrecise();
- switch (memberType) {
- case OBJECT:
- return FrameType.initialized(factory.objectType);
- case BOOLEAN_OR_BYTE:
- return FrameType.initialized(factory.intType);
- case CHAR:
- return FrameType.initialized(factory.intType);
- case SHORT:
- return FrameType.initialized(factory.intType);
- case INT:
- return FrameType.initialized(factory.intType);
- case FLOAT:
- return FrameType.initialized(factory.floatType);
- case LONG:
- return FrameType.longType();
- case DOUBLE:
- return FrameType.doubleType();
- default:
- throw new Unreachable("Unexpected MemberType: " + memberType);
- }
- }
-
- public static FrameType fromNumericType(NumericType numericType, DexItemFactory factory) {
- return FrameType.initialized(numericType.toDexType(factory));
- }
- }
-
- public abstract static class SingletonFrameType extends FrameType {
-
- @Override
- public final boolean equals(Object obj) {
- return this == obj;
- }
-
- @Override
- public final int hashCode() {
- return System.identityHashCode(this);
- }
- }
+ public static final Deque<PreciseFrameType> EMPTY_STACK = ImmutableDeque.of();
@Override
public boolean isFrame() {
@@ -350,680 +69,8 @@
return CfCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
}
- public abstract static class SinglePrimitiveFrameType extends SingletonFrameType
- implements PrimitiveFrameType, SingleFrameType {
-
- public boolean hasIntVerificationType() {
- return false;
- }
-
- @Override
- public final boolean isInitialized() {
- return true;
- }
-
- @Override
- public final boolean isPrimitive() {
- return true;
- }
-
- @Override
- public PrimitiveFrameType asPrimitive() {
- return this;
- }
-
- @Override
- public final SingleFrameType asSingle() {
- return this;
- }
-
- @Override
- public final SinglePrimitiveFrameType asSinglePrimitive() {
- return this;
- }
-
- @Override
- public final SingleFrameType join(SingleFrameType frameType) {
- if (this == frameType) {
- return this;
- }
- if (hasIntVerificationType()
- && frameType.isPrimitive()
- && frameType.asSinglePrimitive().hasIntVerificationType()) {
- return intType();
- }
- return oneWord();
- }
-
- @Override
- public final String toString() {
- return getTypeName();
- }
- }
-
- public static class BooleanFrameType extends SinglePrimitiveFrameType {
-
- private static final BooleanFrameType SINGLETON = new BooleanFrameType();
-
- private BooleanFrameType() {}
-
- @Override
- public DexType getInitializedType(DexItemFactory dexItemFactory) {
- return dexItemFactory.booleanType;
- }
-
- @Override
- public String getTypeName() {
- return "boolean";
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- throw new Unreachable("Unexpected value type: " + this);
- }
-
- @Override
- public boolean hasIntVerificationType() {
- return true;
- }
-
- @Override
- public boolean isBoolean() {
- return true;
- }
- }
-
- public static class ByteFrameType extends SinglePrimitiveFrameType {
-
- private static final ByteFrameType SINGLETON = new ByteFrameType();
-
- private ByteFrameType() {}
-
- @Override
- public DexType getInitializedType(DexItemFactory dexItemFactory) {
- return dexItemFactory.byteType;
- }
-
- @Override
- public String getTypeName() {
- return "byte";
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- throw new Unreachable("Unexpected value type: " + this);
- }
-
- @Override
- public boolean hasIntVerificationType() {
- return true;
- }
-
- @Override
- public boolean isByte() {
- return true;
- }
- }
-
- public static class CharFrameType extends SinglePrimitiveFrameType {
-
- private static final CharFrameType SINGLETON = new CharFrameType();
-
- private CharFrameType() {}
-
- @Override
- public DexType getInitializedType(DexItemFactory dexItemFactory) {
- return dexItemFactory.charType;
- }
-
- @Override
- public String getTypeName() {
- return "char";
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- throw new Unreachable("Unexpected value type: " + this);
- }
-
- @Override
- public boolean hasIntVerificationType() {
- return true;
- }
-
- @Override
- public boolean isChar() {
- return true;
- }
- }
-
- public static class FloatFrameType extends SinglePrimitiveFrameType {
-
- private static final FloatFrameType SINGLETON = new FloatFrameType();
-
- private FloatFrameType() {}
-
- @Override
- public DexType getInitializedType(DexItemFactory dexItemFactory) {
- return dexItemFactory.floatType;
- }
-
- @Override
- public String getTypeName() {
- return "float";
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- return Opcodes.FLOAT;
- }
-
- @Override
- public boolean isFloat() {
- return true;
- }
- }
-
- public static class IntFrameType extends SinglePrimitiveFrameType {
-
- private static final IntFrameType SINGLETON = new IntFrameType();
-
- private IntFrameType() {}
-
- @Override
- public DexType getInitializedType(DexItemFactory dexItemFactory) {
- return dexItemFactory.intType;
- }
-
- @Override
- public String getTypeName() {
- return "int";
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- return Opcodes.INTEGER;
- }
-
- @Override
- public boolean hasIntVerificationType() {
- return true;
- }
-
- @Override
- public boolean isInt() {
- return true;
- }
- }
-
- public static class ShortFrameType extends SinglePrimitiveFrameType {
-
- private static final ShortFrameType SINGLETON = new ShortFrameType();
-
- private ShortFrameType() {}
-
- @Override
- public DexType getInitializedType(DexItemFactory dexItemFactory) {
- return dexItemFactory.shortType;
- }
-
- @Override
- public String getTypeName() {
- return "short";
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- throw new Unreachable("Unexpected value type: " + this);
- }
-
- @Override
- public boolean hasIntVerificationType() {
- return true;
- }
-
- @Override
- public boolean isShort() {
- return true;
- }
- }
-
- public static class SingleInitializedType extends FrameType implements SingleFrameType {
-
- private final DexType type;
-
- private SingleInitializedType(DexType type) {
- assert type != null;
- assert type.isReferenceType();
- this.type = type;
- }
-
- @Override
- public SingleInitializedType asSingleInitializedType() {
- return this;
- }
-
- @Override
- public SingleFrameType join(SingleFrameType frameType) {
- if (equals(frameType)) {
- return this;
- }
- if (frameType.isOneWord() || frameType.isPrimitive() || frameType.isUninitializedObject()) {
- return oneWord();
- }
- DexType otherType = frameType.asSingleInitializedType().getInitializedType();
- assert type != otherType;
- assert type.isReferenceType();
- if (isNullType()) {
- return otherType.isReferenceType() ? frameType : oneWord();
- }
- if (frameType.isNullType()) {
- return this;
- }
- assert type.isArrayType() || type.isClassType();
- assert otherType.isArrayType() || otherType.isClassType();
- // TODO(b/214496607): Implement join of different reference types using class hierarchy.
- throw new Unimplemented();
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- SingleInitializedType initializedType = (SingleInitializedType) obj;
- return type == initializedType.type;
- }
-
- @Override
- public int hashCode() {
- return type.hashCode();
- }
-
- @Override
- public String toString() {
- return "Initialized(" + type.toString() + ")";
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- DexType rewrittenType = graphLens.lookupType(type);
- if (rewrittenType == DexItemFactory.nullValueType) {
- return Opcodes.NULL;
- }
- switch (rewrittenType.toShorty()) {
- case 'L':
- return namingLens.lookupInternalName(rewrittenType);
- case 'I':
- return Opcodes.INTEGER;
- case 'F':
- return Opcodes.FLOAT;
- case 'J':
- return Opcodes.LONG;
- case 'D':
- return Opcodes.DOUBLE;
- default:
- throw new Unreachable("Unexpected value type: " + rewrittenType);
- }
- }
-
- @Override
- public SingleFrameType asSingle() {
- return this;
- }
-
- @Override
- public boolean isWide() {
- return false;
- }
-
- @Override
- public boolean isInitialized() {
- return true;
- }
-
- public DexType getInitializedType() {
- return type;
- }
-
- @Override
- public DexType getInitializedType(DexItemFactory dexItemFactory) {
- return getInitializedType();
- }
-
- @Override
- public boolean isNullType() {
- return type.isNullValueType();
- }
-
- @Override
- public boolean isObject() {
- return type.isReferenceType();
- }
-
- @Override
- public DexType getObjectType(DexType context) {
- assert isObject() : "Unexpected use of getObjectType() for non-object FrameType";
- return type;
- }
- }
-
- public abstract static class WidePrimitiveFrameType extends SingletonFrameType
- implements PrimitiveFrameType, WideFrameType {
-
- @Override
- public boolean isInitialized() {
- return true;
- }
-
- @Override
- public boolean isPrimitive() {
- return true;
- }
-
- @Override
- public PrimitiveFrameType asPrimitive() {
- return this;
- }
-
- @Override
- public boolean isWide() {
- return true;
- }
-
- @Override
- public WideFrameType asWide() {
- return this;
- }
-
- @Override
- public int getWidth() {
- return 2;
- }
-
- @Override
- public WideFrameType join(WideFrameType frameType) {
- return this == frameType ? this : twoWord();
- }
-
- @Override
- public final String toString() {
- return getTypeName();
- }
- }
-
- public static class DoubleFrameType extends WidePrimitiveFrameType {
-
- private static final DoubleFrameType SINGLETON = new DoubleFrameType();
-
- private DoubleFrameType() {}
-
- @Override
- public boolean isDouble() {
- return true;
- }
-
- @Override
- public DexType getInitializedType(DexItemFactory dexItemFactory) {
- return dexItemFactory.doubleType;
- }
-
- @Override
- public String getTypeName() {
- return "double";
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- return Opcodes.DOUBLE;
- }
- }
-
- public static class LongFrameType extends WidePrimitiveFrameType {
-
- private static final LongFrameType SINGLETON = new LongFrameType();
-
- private LongFrameType() {}
-
- @Override
- public boolean isLong() {
- return true;
- }
-
- @Override
- public DexType getInitializedType(DexItemFactory dexItemFactory) {
- return dexItemFactory.longType;
- }
-
- @Override
- public String getTypeName() {
- return "long";
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- return Opcodes.LONG;
- }
- }
-
- private static class UninitializedNew extends FrameType implements SingleFrameType {
-
- private final CfLabel label;
- private final DexType type;
-
- private UninitializedNew(CfLabel label, DexType type) {
- this.label = label;
- this.type = type;
- }
-
- @Override
- public SingleFrameType asSingle() {
- return this;
- }
-
- @Override
- public SingleFrameType join(SingleFrameType frameType) {
- return equals(frameType) ? this : oneWord();
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) {
- return true;
- }
- if (o == null || getClass() != o.getClass()) {
- return false;
- }
- UninitializedNew uninitializedNew = (UninitializedNew) o;
- return label == uninitializedNew.label && type == uninitializedNew.type;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(label, type);
- }
-
- @Override
- public String toString() {
- return "uninitialized new";
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- return label.getLabel();
- }
-
- @Override
- public boolean isObject() {
- return true;
- }
-
- @Override
- public DexType getObjectType(DexType context) {
- return type;
- }
-
- @Override
- public boolean isUninitializedNew() {
- return true;
- }
-
- @Override
- public boolean isUninitializedObject() {
- return true;
- }
-
- @Override
- public CfLabel getUninitializedLabel() {
- return label;
- }
-
- @Override
- public DexType getUninitializedNewType() {
- return type;
- }
- }
-
- private static class UninitializedThis extends SingletonFrameType implements SingleFrameType {
-
- private static final UninitializedThis SINGLETON = new UninitializedThis();
-
- private UninitializedThis() {}
-
- @Override
- public SingleFrameType asSingle() {
- return this;
- }
-
- @Override
- public SingleFrameType join(SingleFrameType frameType) {
- if (this == frameType) {
- return this;
- }
- return oneWord();
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- return Opcodes.UNINITIALIZED_THIS;
- }
-
- @Override
- public String toString() {
- return "uninitialized this";
- }
-
- @Override
- public boolean isObject() {
- return true;
- }
-
- @Override
- public DexType getObjectType(DexType context) {
- return context;
- }
-
- @Override
- public boolean isUninitializedObject() {
- return true;
- }
-
- @Override
- public boolean isUninitializedThis() {
- return true;
- }
- }
-
- private static class OneWord extends SingletonFrameType implements SingleFrameType {
-
- private static final OneWord SINGLETON = new OneWord();
-
- private OneWord() {}
-
- @Override
- public boolean isOneWord() {
- return true;
- }
-
- @Override
- public boolean isSpecific() {
- return false;
- }
-
- @Override
- public SingleFrameType asSingle() {
- return this;
- }
-
- @Override
- public SingleFrameType join(SingleFrameType frameType) {
- return this;
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- return Opcodes.TOP;
- }
-
- @Override
- public String toString() {
- return "oneword";
- }
- }
-
- private static class TwoWord extends SingletonFrameType implements WideFrameType {
-
- private static final TwoWord SINGLETON = new TwoWord();
-
- private TwoWord() {}
-
- @Override
- public boolean isSpecific() {
- return false;
- }
-
- @Override
- public boolean isTwoWord() {
- return true;
- }
-
- @Override
- public boolean isWide() {
- return true;
- }
-
- @Override
- public WideFrameType asWide() {
- return this;
- }
-
- @Override
- public int getWidth() {
- return 2;
- }
-
- @Override
- public WideFrameType join(WideFrameType frameType) {
- // The join of wide with one of {double, long, wide} is wide.
- return this;
- }
-
- @Override
- Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
- throw new Unreachable("Should only be used for verification");
- }
-
- @Override
- public String toString() {
- return "twoword";
- }
- }
-
private final Int2ObjectSortedMap<FrameType> locals;
- private final Deque<FrameType> stack;
+ private final Deque<PreciseFrameType> stack;
// Constructor used by CfCodePrinter.
public CfFrame() {
@@ -1037,20 +84,20 @@
}
// Constructor used by CfCodePrinter.
- public CfFrame(Deque<FrameType> stack) {
+ public CfFrame(Deque<PreciseFrameType> stack) {
this(EMPTY_LOCALS, stack);
assert !stack.isEmpty() || stack == EMPTY_STACK : "Should use EMPTY_STACK instead";
}
// Constructor used by CfCodePrinter.
- public CfFrame(Int2ObjectAVLTreeMap<FrameType> locals, Deque<FrameType> stack) {
+ public CfFrame(Int2ObjectAVLTreeMap<FrameType> locals, Deque<PreciseFrameType> stack) {
this((Int2ObjectSortedMap<FrameType>) locals, stack);
assert !locals.isEmpty() || locals == EMPTY_LOCALS : "Should use EMPTY_LOCALS instead";
assert !stack.isEmpty() || stack == EMPTY_STACK : "Should use EMPTY_STACK instead";
}
// Internal constructor that does not require locals to be of the type Int2ObjectAVLTreeMap.
- private CfFrame(Int2ObjectSortedMap<FrameType> locals, Deque<FrameType> stack) {
+ private CfFrame(Int2ObjectSortedMap<FrameType> locals, Deque<PreciseFrameType> stack) {
assert locals.values().stream().allMatch(Objects::nonNull);
assert stack.stream().allMatch(Objects::nonNull);
this.locals = locals;
@@ -1087,13 +134,13 @@
return (Int2ObjectAVLTreeMap<FrameType>) locals;
}
- public Deque<FrameType> getStack() {
+ public Deque<PreciseFrameType> getStack() {
return stack;
}
- public ArrayDeque<FrameType> getMutableStack() {
+ public ArrayDeque<PreciseFrameType> getMutableStack() {
assert stack instanceof ArrayDeque<?>;
- return (ArrayDeque<FrameType>) stack;
+ return (ArrayDeque<PreciseFrameType>) stack;
}
@Override
@@ -1112,7 +159,7 @@
public int hashCode() {
// Generates a hash that is identical to Objects.hash(locals, stack[0], ..., stack[n]).
int result = 31 + locals.hashCode();
- for (FrameType frameType : stack) {
+ for (PreciseFrameType frameType : stack) {
result = 31 * result + frameType.hashCode();
}
return result;
@@ -1146,7 +193,7 @@
public int computeStackSize() {
int size = 0;
- for (FrameType frameType : stack) {
+ for (PreciseFrameType frameType : stack) {
size += frameType.getWidth();
}
return size;
@@ -1159,7 +206,7 @@
}
Object[] stackTypes = new Object[stackCount];
int index = 0;
- for (FrameType frameType : stack) {
+ for (PreciseFrameType frameType : stack) {
stackTypes[index++] = frameType.getTypeOpcode(graphLens, namingLens);
}
return stackTypes;
@@ -1227,15 +274,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- frameBuilder.checkFrameAndSet(this);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
@@ -1244,28 +282,8 @@
return frame.check(appView, this);
}
- public CfFrame markInstantiated(FrameType uninitializedType, DexType initType) {
- if (uninitializedType.isInitialized()) {
- throw CfCodeStackMapValidatingException.error(
- "Cannot instantiate already instantiated type " + uninitializedType);
- }
- CfFrame.Builder builder = CfFrame.builder().allocateStack(stack.size());
- forEachLocal(
- (localIndex, frameType) ->
- builder.store(
- localIndex, getInitializedFrameType(uninitializedType, frameType, initType)));
- for (FrameType frameType : stack) {
- builder.push(getInitializedFrameType(uninitializedType, frameType, initType));
- }
- return builder.build();
- }
-
- public static FrameType getInitializedFrameType(
- FrameType unInit, FrameType other, DexType newType) {
- assert !unInit.isInitialized();
- if (other.isInitialized()) {
- return other;
- }
+ public static PreciseFrameType getInitializedFrameType(
+ UninitializedFrameType unInit, UninitializedFrameType other, DexType newType) {
if (unInit.isUninitializedThis() && other.isUninitializedThis()) {
return FrameType.initialized(newType);
}
@@ -1280,16 +298,16 @@
public CfFrame map(java.util.function.Function<DexType, DexType> func) {
boolean mapped = false;
for (int var : locals.keySet()) {
- CfFrame.FrameType originalType = locals.get(var);
- CfFrame.FrameType mappedType = originalType.map(func);
+ FrameType originalType = locals.get(var);
+ FrameType mappedType = originalType.map(func);
mapped = originalType != mappedType;
if (mapped) {
break;
}
}
if (!mapped) {
- for (FrameType frameType : stack) {
- CfFrame.FrameType mappedType = frameType.map(func);
+ for (PreciseFrameType frameType : stack) {
+ PreciseFrameType mappedType = frameType.map(func);
mapped = frameType != mappedType;
if (mapped) {
break;
@@ -1303,7 +321,7 @@
for (Int2ObjectMap.Entry<FrameType> entry : locals.int2ObjectEntrySet()) {
builder.store(entry.getIntKey(), entry.getValue().map(func));
}
- for (FrameType frameType : stack) {
+ for (PreciseFrameType frameType : stack) {
builder.push(frameType.map(func));
}
return builder.build();
@@ -1312,7 +330,7 @@
public static class Builder {
private Int2ObjectSortedMap<FrameType> locals = EMPTY_LOCALS;
- private Deque<FrameType> stack = EMPTY_STACK;
+ private Deque<PreciseFrameType> stack = EMPTY_STACK;
private boolean hasIncompleteUninitializedNew = false;
private boolean seenStore = false;
@@ -1355,7 +373,7 @@
return locals.get(localIndex);
}
- public Builder push(FrameType frameType) {
+ public Builder push(PreciseFrameType frameType) {
ensureMutableStack();
stack.addLast(frameType);
return this;
@@ -1366,7 +384,7 @@
return this;
}
- public Builder setStack(Deque<FrameType> stack) {
+ public Builder setStack(Deque<PreciseFrameType> stack) {
this.stack = stack;
return this;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
index be448f1..7c73bbb 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
@@ -4,52 +4,60 @@
package com.android.tools.r8.cf.code;
-import static com.android.tools.r8.utils.BiPredicateUtils.or;
-
import com.android.tools.r8.cf.code.CfAssignability.AssignabilityResult;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.cf.code.frame.PreciseFrameType;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.CfCodeDiagnostics;
import com.android.tools.r8.graph.CfCodeStackMapValidatingException;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
+import com.android.tools.r8.optimize.interfaces.analysis.ConcreteCfFrameState;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.collections.ImmutableDeque;
import com.google.common.collect.Sets;
-import it.unimi.dsi.fastutil.ints.Int2ObjectSortedMap;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.function.BiPredicate;
-public class CfFrameVerificationHelper {
-
- private static final CfFrame NO_FRAME = new CfFrame();
+public class CfFrameVerificationHelper implements CfAnalysisConfig {
private final AppView<?> appView;
+ private final CfCode code;
+ private final GraphLens codeLens;
private final DexItemFactory factory;
+ private final ProgramMethod method;
+ private final DexMethod previousMethod;
- private CfFrame currentFrame = NO_FRAME;
- private final DexType context;
private final Map<CfLabel, CfFrame> stateMap;
private final List<CfTryCatch> tryCatchRanges;
- private final int maxStackHeight;
private final Deque<CfTryCatch> currentCatchRanges = new ArrayDeque<>();
private final Set<CfLabel> tryCatchRangeLabels;
public CfFrameVerificationHelper(
AppView<?> appView,
- DexType context,
+ CfCode code,
+ ProgramMethod method,
Map<CfLabel, CfFrame> stateMap,
- List<CfTryCatch> tryCatchRanges,
- int maxStackHeight) {
+ List<CfTryCatch> tryCatchRanges) {
this.appView = appView;
- this.context = context;
+ this.code = code;
+ this.codeLens = code.getCodeLens(appView);
+ this.method = method;
+ this.previousMethod =
+ appView.graphLens().getOriginalMethodSignature(method.getReference(), codeLens);
this.stateMap = stateMap;
this.tryCatchRanges = tryCatchRanges;
this.factory = appView.dexItemFactory();
- this.maxStackHeight = maxStackHeight;
// Compute all labels that marks a start or end to catch ranges.
tryCatchRangeLabels = Sets.newIdentityHashSet();
for (CfTryCatch tryCatchRange : tryCatchRanges) {
@@ -58,106 +66,36 @@
}
}
- public FrameType readLocal(int index, DexType expectedType) {
- checkFrameIsSet();
- FrameType frameType = currentFrame.getLocals().get(index);
- if (frameType == null) {
- throw CfCodeStackMapValidatingException.error("No local at index " + index);
+ @Override
+ public DexMethod getCurrentContext() {
+ return previousMethod;
+ }
+
+ @Override
+ public int getMaxLocals() {
+ return code.getMaxLocals();
+ }
+
+ @Override
+ public int getMaxStack() {
+ return code.getMaxStack();
+ }
+
+ @Override
+ public boolean isImmediateSuperClassOfCurrentContext(DexType type) {
+ // If the code is rewritten according to the graph lens, we perform a strict check that the
+ // given type is the same as the current holder's super class.
+ if (codeLens == appView.graphLens()) {
+ return type == method.getHolder().getSuperType();
}
- checkIsAssignable(
- frameType,
- expectedType,
- or(
- this::isUninitializedThisAndTarget,
- this::isUninitializedNewAndTarget,
- this::isAssignableAndInitialized));
- return frameType;
+ // Otherwise, we don't know what the super class of the current class was at the point of the
+ // code lens. We return true, which has the consequence that we may accept a constructor call
+ // for an uninitialized-this value where the constructor is not defined in the immediate parent
+ // class.
+ return true;
}
- public void storeLocal(int index, FrameType frameType) {
- checkFrameIsSet();
- currentFrame.getLocals().put(index, frameType);
- }
-
- public FrameType pop() {
- checkFrameIsSet();
- if (currentFrame.getStack().isEmpty()) {
- throw CfCodeStackMapValidatingException.error("Cannot pop() from an empty stack");
- }
- return currentFrame.getStack().removeLast();
- }
-
- public FrameType popInitialized(DexType expectedType) {
- return pop(expectedType, this::isAssignableAndInitialized);
- }
-
- public FrameType pop(DexType expectedType, BiPredicate<FrameType, DexType> isAssignable) {
- FrameType frameType = pop();
- checkIsAssignable(frameType, expectedType, isAssignable);
- return frameType;
- }
-
- public CfFrameVerificationHelper popAndDiscardInitialized(DexType expectedType) {
- checkFrameIsSet();
- popInitialized(expectedType);
- return this;
- }
-
- public CfFrameVerificationHelper popAndDiscardInitialized(DexType... expectedTypes) {
- checkFrameIsSet();
- for (int i = expectedTypes.length - 1; i >= 0; i--) {
- popInitialized(expectedTypes[i]);
- }
- return this;
- }
-
- public FrameType pop(FrameType expectedType) {
- FrameType frameType = pop();
- checkIsAssignable(frameType, expectedType);
- return frameType;
- }
-
- public CfFrameVerificationHelper popAndDiscard(FrameType... expectedTypes) {
- checkFrameIsSet();
- for (int i = expectedTypes.length - 1; i >= 0; i--) {
- pop(expectedTypes[i]);
- }
- return this;
- }
-
- public void popAndInitialize(DexType context, DexType methodHolder) {
- checkFrameIsSet();
- FrameType objectRef =
- pop(
- factory.objectType,
- or(this::isUninitializedThisAndTarget, this::isUninitializedNewAndTarget));
- CfFrame newFrame =
- currentFrame.markInstantiated(
- objectRef, objectRef.isUninitializedNew() ? methodHolder : context);
- setNoFrame();
- checkFrameAndSet(newFrame);
- }
-
- public CfFrameVerificationHelper push(FrameType type) {
- checkFrameIsSet();
- currentFrame.getStack().addLast(type);
- if (currentFrame.computeStackSize() > maxStackHeight) {
- throw CfCodeStackMapValidatingException.error(
- "The max stack height of "
- + maxStackHeight
- + " is violated when pushing type "
- + type
- + " to existing stack of size "
- + currentFrame.getStack().size());
- }
- return this;
- }
-
- public CfFrameVerificationHelper push(DexType type) {
- return push(FrameType.initialized(type));
- }
-
- public CfFrameVerificationHelper seenLabel(CfLabel label) {
+ public void seenLabel(CfLabel label) {
if (tryCatchRangeLabels.contains(label)) {
for (CfTryCatch tryCatchRange : tryCatchRanges) {
if (tryCatchRange.start == label) {
@@ -166,148 +104,109 @@
}
currentCatchRanges.removeIf(currentRange -> currentRange.end == label);
}
- return this;
}
- public void checkTryCatchRange(CfTryCatch tryCatchRange) {
+ public CfCodeDiagnostics checkTryCatchRanges() {
+ for (CfTryCatch tryCatchRange : tryCatchRanges) {
+ CfCodeDiagnostics diagnostics = checkTryCatchRange(tryCatchRange);
+ if (diagnostics != null) {
+ return diagnostics;
+ }
+ }
+ return null;
+ }
+
+ public CfCodeDiagnostics checkTryCatchRange(CfTryCatch tryCatchRange) {
// According to the spec:
// https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1
// saying ` and the handler's target (the initial instruction of the handler code) is type
// safe assuming an incoming type state T. The type state T is derived from ExcStackFrame
// by replacing the operand stack with a stack whose sole element is the handler's
// exception class.
- tryCatchRange.targets.forEach(
- target -> {
- CfFrame destinationFrame = stateMap.get(target);
- if (destinationFrame == null) {
- throw CfCodeStackMapValidatingException.error("No frame for target catch range target");
- }
- // From the spec: the handler's exception class is assignable to the class Throwable.
- tryCatchRange.guards.forEach(
- guard -> {
- if (!CfAssignability.isAssignable(guard, factory.throwableType, appView)) {
- throw CfCodeStackMapValidatingException.error(
- "Could not assign '" + guard.toSourceString() + "' to throwable.");
- }
- checkStackIsAssignable(
- ImmutableDeque.of(FrameType.initialized(guard)), destinationFrame.getStack());
- });
- });
- }
-
- private void checkFrameIsSet() {
- if (currentFrame == NO_FRAME) {
- throw CfCodeStackMapValidatingException.error("Unexpected state change");
- }
- }
-
- public void checkFrameAndSet(CfFrame newFrame) {
- if (currentFrame != NO_FRAME) {
- checkFrame(newFrame);
- }
- setFrame(newFrame);
- }
-
- private void setFrame(CfFrame frame) {
- assert frame != NO_FRAME;
- currentFrame = frame.mutableCopy();
- }
-
- public void checkExceptionEdges() {
- for (CfTryCatch currentCatchRange : currentCatchRanges) {
- for (CfLabel target : currentCatchRange.targets) {
- CfFrame destinationFrame = stateMap.get(target);
- if (destinationFrame == null) {
- throw CfCodeStackMapValidatingException.error("No frame for target catch range target");
+ for (CfLabel target : tryCatchRange.getTargets()) {
+ CfFrame destinationFrame = stateMap.get(target);
+ if (destinationFrame == null) {
+ return CfCodeStackMapValidatingException.invalidTryCatchRange(
+ method, tryCatchRange, "No frame for target catch range target", appView);
+ }
+ // From the spec: the handler's exception class is assignable to the class Throwable.
+ for (DexType guard : tryCatchRange.guards) {
+ if (!CfAssignability.isAssignable(guard, factory.throwableType, appView)) {
+ return CfCodeStackMapValidatingException.invalidTryCatchRange(
+ method,
+ tryCatchRange,
+ "Could not assign " + guard.getTypeName() + " to java.lang.Throwable",
+ appView);
}
- checkLocalsIsAssignable(currentFrame.getLocals(), destinationFrame.getLocals());
+ Deque<PreciseFrameType> sourceStack = ImmutableDeque.of(FrameType.initialized(guard));
+ AssignabilityResult assignabilityResult =
+ CfAssignability.isStackAssignable(sourceStack, destinationFrame.getStack(), appView);
+ if (assignabilityResult.isFailed()) {
+ return CfCodeStackMapValidatingException.invalidTryCatchRange(
+ method, tryCatchRange, assignabilityResult.asFailed().getMessage(), appView);
+ }
}
}
+ return null;
}
- public CfFrame getFrame() {
- return currentFrame;
- }
-
- public void checkTarget(CfLabel label) {
- checkFrame(stateMap.get(label));
- }
-
- public void checkFrame(CfFrame destinationFrame) {
- if (destinationFrame == null) {
- throw CfCodeStackMapValidatingException.error("No destination frame");
+ public CfFrameState checkExceptionEdges(CfFrameState state) {
+ for (CfTryCatch currentCatchRange : currentCatchRanges) {
+ for (CfLabel target : currentCatchRange.getTargets()) {
+ CfFrame destinationFrame = stateMap.get(target);
+ if (destinationFrame == null) {
+ return CfFrameState.error("No frame for target catch range target");
+ }
+ state = state.checkLocals(appView, destinationFrame);
+ }
}
- checkFrame(destinationFrame.getLocals(), destinationFrame.getStack());
+ return state;
}
- public void checkFrame(Int2ObjectSortedMap<FrameType> locals, Deque<FrameType> stack) {
- checkIsAssignable(currentFrame.getLocals(), currentFrame.getStack(), locals, stack);
+ public CfFrameState checkTarget(CfFrameState state, CfLabel label) {
+ CfFrame destinationFrame = getDestinationFrame(label);
+ return destinationFrame != null
+ ? state.checkLocals(appView, destinationFrame).checkStack(appView, destinationFrame)
+ : CfFrameState.error("No destination frame");
}
- public void setNoFrame() {
- currentFrame = NO_FRAME;
+ private CfFrame getDestinationFrame(CfLabel label) {
+ return stateMap.get(label);
}
- public boolean isUninitializedThisAndTarget(FrameType source, DexType target) {
- if (!source.isUninitializedThis()) {
- return false;
+ public TraversalContinuation<CfCodeDiagnostics, CfFrameState> computeStateForNextInstruction(
+ CfInstruction instruction, int instructionIndex, CfFrameState state) {
+ if (!instruction.isJump()) {
+ return TraversalContinuation.doContinue(state);
}
- return target == factory.objectType || target == context;
- }
-
- public boolean isUninitializedNewAndTarget(FrameType source, DexType target) {
- if (!source.isUninitializedNew()) {
- return false;
+ if (instructionIndex == code.getInstructions().size() - 1) {
+ return TraversalContinuation.doContinue(CfFrameState.bottom());
}
- return target == factory.objectType || target == context;
- }
-
- public boolean isAssignableAndInitialized(FrameType source, DexType target) {
- if (!source.isInitialized()) {
- return false;
+ if (instructionIndex == code.getInstructions().size() - 2
+ && code.getInstructions().get(instructionIndex + 1).isLabel()) {
+ return TraversalContinuation.doContinue(CfFrameState.bottom());
}
- return CfAssignability.isAssignable(source.getInitializedType(factory), target, appView);
- }
-
- public void checkIsAssignable(
- FrameType source, DexType target, BiPredicate<FrameType, DexType> predicate) {
- if (predicate.test(source, target)) {
- return;
+ if (instruction.asJump().hasFallthrough()) {
+ return TraversalContinuation.doContinue(state);
}
- throw CfCodeStackMapValidatingException.error(
- "The expected type " + source + " is not assignable to " + target.toSourceString());
- }
-
- public void checkIsAssignable(FrameType source, FrameType target) {
- if (!CfAssignability.isFrameTypeAssignable(source, target, appView)) {
- throw CfCodeStackMapValidatingException.error(
- "The expected type " + source + " is not assignable to " + target);
+ int nextInstructionIndex = instructionIndex + 1;
+ CfInstruction nextInstruction = code.getInstructions().get(nextInstructionIndex);
+ CfFrame nextFrame = null;
+ if (nextInstruction.isFrame()) {
+ nextFrame = nextInstruction.asFrame();
+ } else if (nextInstruction.isLabel()) {
+ nextFrame = getDestinationFrame(nextInstruction.asLabel());
}
- }
-
- // Based on https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1.4.
- private void checkIsAssignable(
- Int2ObjectSortedMap<FrameType> sourceLocals,
- Deque<FrameType> sourceStack,
- Int2ObjectSortedMap<FrameType> destLocals,
- Deque<FrameType> destStack) {
- checkLocalsIsAssignable(sourceLocals, destLocals);
- checkStackIsAssignable(sourceStack, destStack);
- }
-
- private void checkLocalsIsAssignable(
- Int2ObjectSortedMap<FrameType> sourceLocals, Int2ObjectSortedMap<FrameType> destLocals) {
- AssignabilityResult result =
- CfAssignability.isLocalsAssignable(sourceLocals, destLocals, appView);
- if (result.isFailed()) {
- throw CfCodeStackMapValidatingException.error(result.asFailed().getMessage());
+ if (nextFrame != null) {
+ CfFrame currentFrameCopy = nextFrame.mutableCopy();
+ return TraversalContinuation.doContinue(
+ new ConcreteCfFrameState(
+ currentFrameCopy.getMutableLocals(),
+ currentFrameCopy.getMutableStack(),
+ currentFrameCopy.computeStackSize()));
}
- }
-
- private void checkStackIsAssignable(Deque<FrameType> sourceStack, Deque<FrameType> destStack) {
- AssignabilityResult result = CfAssignability.isStackAssignable(sourceStack, destStack, appView);
- if (result.isFailed()) {
- throw CfCodeStackMapValidatingException.error(result.asFailed().getMessage());
- }
+ return TraversalContinuation.doBreak(
+ CfCodeStackMapValidatingException.invalidStackMapForInstruction(
+ method, nextInstructionIndex, nextInstruction, "Expected frame instruction", appView));
}
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
index 490de77..e00ee93 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -109,15 +108,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // Intentionally empty.
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIf.java b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
index 78acd72..216543f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -102,20 +101,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., value →
- // ...
- frameBuilder.popAndDiscardInitialized(
- type.isObject()
- ? dexItemFactory.objectType
- : type.toPrimitiveType().toDexType(dexItemFactory));
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
index 96f5832..2a2e561 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
@@ -8,8 +8,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -105,18 +103,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., value1, value2 →
- // ...
- DexType type = this.type.toDexType(dexItemFactory);
- frameBuilder.popAndDiscardInitialized(type, type);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
index 8135aa9..3267d60 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -99,15 +98,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- frameBuilder.readLocal(var, dexItemFactory.intType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
index fe8f36e..e253413 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -117,17 +116,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., →
- // ..., value
- frameBuilder.push(dexItemFactory.intType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
index 1eb4b5d..cfd7afa 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldRead.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
@@ -68,17 +67,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., objectref →
- // ..., value
- frameBuilder.popAndDiscardInitialized(getField().getHolderType()).push(getField().getType());
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
index b7bf3ec..d18681f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceFieldWrite.java
@@ -5,15 +5,13 @@
package com.android.tools.r8.cf.code;
import static com.android.tools.r8.optimize.interfaces.analysis.ErroneousCfFrameState.formatActual;
-import static com.android.tools.r8.utils.BiPredicateUtils.or;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.cf.code.frame.PreciseFrameType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
@@ -68,23 +66,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., objectref, value →
- // ...
- frameBuilder
- .popAndDiscardInitialized(getField().getType())
- .pop(
- getField().getHolderType(),
- or(
- frameBuilder::isUninitializedThisAndTarget,
- frameBuilder::isAssignableAndInitialized));
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
@@ -101,7 +82,7 @@
(state, head) -> head.isUninitializedNew() ? error(head) : state);
}
- private ErroneousCfFrameState error(FrameType objectType) {
+ private ErroneousCfFrameState error(PreciseFrameType objectType) {
return CfFrameState.error(
"Frame type "
+ formatActual(objectType)
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index e42e7e3..80da4fe 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -127,17 +126,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., objectref →
- // ..., result
- frameBuilder.popAndDiscardInitialized(dexItemFactory.objectType).push(dexItemFactory.intType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index dc1f4de..932a283 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.graph.ClasspathMethod;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -354,12 +353,6 @@
public abstract ConstraintWithTarget inliningConstraint(
InliningConstraints inliningConstraints, CfCode code, ProgramMethod context);
- public abstract void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory);
-
public abstract CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index bbaf8b5..ffbd427 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -316,30 +316,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., objectref, [arg1, [arg2 ...]] →
- // ... [ returnType ]
- // OR, for static method calls:
- // ..., [arg1, [arg2 ...]] →
- // ...
- frameBuilder.popAndDiscardInitialized(method.proto.parameters.values);
- if (opcode == Opcodes.INVOKESPECIAL
- && (method.isInstanceInitializer(dexItemFactory)
- || method.mustBeInlinedIntoInstanceInitializer(appView))) {
- frameBuilder.popAndInitialize(context.getHolderType(), method.holder);
- } else if (opcode != Opcodes.INVOKESTATIC) {
- frameBuilder.popInitialized(method.holder);
- }
- if (!method.getReturnType().isVoidType()) {
- frameBuilder.push(method.getReturnType());
- }
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
index dc81cfc..a716425 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
@@ -168,20 +167,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., [arg1, [arg2 ...]] →
- // ...
- frameBuilder.popAndDiscardInitialized(callSite.methodProto.parameters.values);
- if (callSite.methodProto.returnType != dexItemFactory.voidType) {
- frameBuilder.push(callSite.methodProto.returnType);
- }
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
index f132e94..698e91d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -7,10 +7,8 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.CfCodeStackMapValidatingException;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -85,17 +83,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // JSR/RET instructions cannot be verified since we have not type-checking way for addresses
- // on the stack/locals. We have to abandon.
- throw CfCodeStackMapValidatingException.error("Unexpected JSR/RET instruction");
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
index 7705bce..011f97e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -97,15 +96,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // Intentionally empty.
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
index 22e8e44..6831f06 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -4,12 +4,12 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -24,6 +24,7 @@
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.optimize.interfaces.analysis.CfAnalysisConfig;
import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
+import com.android.tools.r8.optimize.interfaces.analysis.ErroneousCfFrameState;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -127,22 +128,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ... →
- // ..., objectref
- frameBuilder.push(
- frameBuilder.readLocal(
- getLocalIndex(),
- type.isObject()
- ? dexItemFactory.objectType
- : type.toPrimitiveType().toDexType(dexItemFactory)));
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
@@ -151,6 +136,21 @@
// ... →
// ..., objectref
return frame.readLocal(
- appView, getLocalIndex(), type, (state, frameType) -> state.push(config, frameType));
+ appView,
+ getLocalIndex(),
+ type,
+ (state, frameType) ->
+ frameType.isPrecise() ? state.push(config, frameType.asPrecise()) : error(frameType));
+ }
+
+ private ErroneousCfFrameState error(FrameType frameType) {
+ assert frameType.isOneWord() || frameType.isTwoWord();
+ StringBuilder message =
+ new StringBuilder("Unexpected attempt to read local of type top at index ")
+ .append(getLocalIndex());
+ if (type.isWide()) {
+ message.append(" and ").append(getLocalIndex() + 1);
+ }
+ return CfFrameState.error(message.toString());
}
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
index 18bf0d3..8109ca3 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
@@ -4,13 +4,11 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -179,28 +177,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., value1, value2 →
- // ..., result
- FrameType value1Type = FrameType.fromNumericType(type, dexItemFactory);
- FrameType value2Type;
- switch (opcode) {
- case And:
- case Or:
- case Xor:
- value2Type = value1Type;
- break;
- default:
- value2Type = FrameType.initialized(dexItemFactory.intType);
- }
- frameBuilder.popAndDiscard(value1Type, value2Type).push(value1Type);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
index 9b6e582..f225050 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
@@ -4,12 +4,10 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -96,17 +94,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., objectref →
- // ...
- frameBuilder.pop(FrameType.initialized(dexItemFactory.objectType));
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
index 0d48a12..4c55cc4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -130,20 +129,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., count1, [count2, ...] →
- // ..., arrayref
- for (int i = 0; i < dimensions; i++) {
- frameBuilder.popInitialized(dexItemFactory.intType);
- }
- frameBuilder.push(type);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
index 5150a97..bbed094 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
@@ -4,13 +4,11 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -121,18 +119,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., value →
- // ..., result
- FrameType frameType = FrameType.fromNumericType(type, dexItemFactory);
- frameBuilder.popAndDiscard(frameType).push(frameType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
index 94fbd54..ec6d665 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -4,13 +4,12 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -133,17 +132,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ... →
- // ..., objectref
- frameBuilder.push(FrameType.uninitializedNew(getLabel(), type));
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
index 6d176fa..55a451f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -166,17 +165,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., count →
- // ..., arrayref
- frameBuilder.popAndDiscardInitialized(dexItemFactory.intType).push(type);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
index 7814564..febd00e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewUnboxedEnum.java
@@ -4,14 +4,12 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -119,17 +117,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ... →
- // ..., objectref
- frameBuilder.push(FrameType.initialized(type));
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNop.java b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
index db3ea6a..1e1cc75 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -78,15 +77,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // This is an actual Nop.
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
index f302df8..8b0e54e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
@@ -4,13 +4,11 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -192,19 +190,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., value →
- // ..., result
- frameBuilder
- .popAndDiscard(FrameType.fromNumericType(from, dexItemFactory))
- .push(FrameType.fromNumericType(to, dexItemFactory));
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
index 1df0826..f6d2d6c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -111,15 +110,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // This is a no-op.
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
index 2d2456e..18728fd 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfRecordFieldValues.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -111,18 +110,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- for (DexField ignored : fields) {
- frameBuilder.popInitialized(dexItemFactory.objectType);
- }
- frameBuilder.push(dexItemFactory.objectArrayType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
index 6c007cc..1bb122a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -119,17 +118,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- assert !context.getReturnType().isVoidType();
- frameBuilder.popAndDiscardInitialized(context.getReturnType());
- frameBuilder.setNoFrame();
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
index e21e6c7..fa1227c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -93,15 +92,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- frameBuilder.setNoFrame();
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
index 345cc84..6971f49 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
@@ -4,14 +4,12 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -356,159 +354,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- switch (opcode) {
- case Pop:
- // ..., value →
- // ...
- frameBuilder.pop(FrameType.oneWord());
- return;
- case Pop2:
- // ..., value2, value1 →
- // ...
- // or, for double and long:
- // ..., value →
- // ...
- final FrameType pop = frameBuilder.pop();
- if (pop.isSingle()) {
- frameBuilder.pop(FrameType.oneWord());
- }
- return;
- case Dup:
- {
- // ..., value →
- // ..., value, value
- FrameType topValue = frameBuilder.pop(FrameType.oneWord());
- frameBuilder.push(topValue).push(topValue);
- return;
- }
- case DupX1:
- {
- // ..., value2, value1 →
- // ..., value1, value2, value1
- FrameType value1 = frameBuilder.pop(FrameType.oneWord());
- FrameType value2 = frameBuilder.pop(FrameType.oneWord());
- frameBuilder.push(value1).push(value2).push(value1);
- return;
- }
- case DupX2:
- {
- // ..., value3, value2, value1 →
- // ..., value1, value3, value2, value1
- // or, if value2 is double or long:
- // ..., value2, value1 →
- // ..., value1, value2, value1
- FrameType value1 = frameBuilder.pop(FrameType.oneWord());
- FrameType value2 = frameBuilder.pop();
- if (value2.isSingle()) {
- FrameType value3 = frameBuilder.pop(FrameType.oneWord());
- frameBuilder.push(value1).push(value3);
- } else {
- frameBuilder.push(value1);
- }
- frameBuilder.push(value2).push(value1);
- return;
- }
- case Dup2:
- {
- // ..., value2, value1 →
- // ..., value2, value1, value2, value1
- // or, for value1 being long or double:
- // ..., value →
- // ..., value, value
- FrameType value1 = frameBuilder.pop();
- if (value1.isSingle()) {
- FrameType value2 = frameBuilder.pop(FrameType.oneWord());
- frameBuilder.push(value2).push(value1).push(value2);
- } else {
- frameBuilder.push(value1);
- }
- frameBuilder.push(value1);
- return;
- }
- case Dup2X1:
- {
- // ..., value3, value2, value1 →
- // ..., value2, value1, value3, value2, value1
- // or, for value1 being a long or double:
- // ..., value2, value1 →
- // ..., value1, value2, value1
- FrameType value1 = frameBuilder.pop();
- FrameType value2 = frameBuilder.pop(FrameType.oneWord());
- if (value1.isSingle()) {
- FrameType value3 = frameBuilder.pop(FrameType.oneWord());
- frameBuilder.push(value2).push(value1).push(value3);
- } else {
- frameBuilder.push(value1);
- }
- frameBuilder.push(value2);
- frameBuilder.push(value1);
- return;
- }
- case Dup2X2:
- {
- // (1)
- // ..., value4, value3, value2, value1 →
- // ..., value2, value1, value4, value3, value2, value1
- // (2) OR, if value1 is long or double
- // ..., value3, value2, value1 →
- // ..., value1, value3, value2, value1
- // (3) OR if value3 is long or double
- // ..., value3, value2, value1 →
- // ..., value2, value1, value3, value2, value1
- // (4) OR, where value1 and value2 is double or long:
- // ..., value2, value1 →
- // ..., value1, value2, value1
- FrameType value1 = frameBuilder.pop();
- if (value1.isSingle()) {
- FrameType value2 = frameBuilder.pop(FrameType.oneWord());
- FrameType value3 = frameBuilder.pop();
- if (value3.isSingle()) {
- // (1)
- FrameType value4 = frameBuilder.pop(FrameType.oneWord());
- frameBuilder
- .push(value2)
- .push(value1)
- .push(value4)
- .push(value3)
- .push(value2)
- .push(value1);
- } else {
- // (3)
- frameBuilder.push(value2).push(value1).push(value3).push(value2).push(value1);
- }
- } else {
- FrameType value2 = frameBuilder.pop();
- if (value2.isSingle()) {
- // (2)
- FrameType value3 = frameBuilder.pop(FrameType.oneWord());
- frameBuilder.push(value1).push(value3).push(value2).push(value1);
- } else {
- // (4)
- frameBuilder.push(value1).push(value2).push(value1);
- }
- }
- return;
- }
- case Swap:
- {
- // ..., value2, value1 →
- // ..., value1, value2
- FrameType value1 = frameBuilder.pop(FrameType.oneWord());
- FrameType value2 = frameBuilder.pop(FrameType.oneWord());
- frameBuilder.push(value1).push(value2);
- return;
- }
- default:
- throw new Unreachable("Invalid opcode for CfStackInstruction");
- }
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
index e0d1ab1..c60a5fe 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldRead.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
@@ -71,17 +70,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., →
- // ..., value
- frameBuilder.push(getField().getType());
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
index dc25d3f..fa7df86 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStaticFieldWrite.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
@@ -67,17 +66,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., value →
- // ...
- frameBuilder.popAndDiscardInitialized(getField().getType());
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
index e5406bb..1015a15 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -3,16 +3,12 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.cf.code;
-import static com.android.tools.r8.utils.BiPredicateUtils.or;
-
import com.android.tools.r8.cf.CfPrinter;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -129,53 +125,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., ref →
- // ...
- FrameType pop = frameBuilder.pop();
- switch (type) {
- case OBJECT:
- frameBuilder.checkIsAssignable(
- pop,
- dexItemFactory.objectType,
- or(
- frameBuilder::isUninitializedThisAndTarget,
- frameBuilder::isUninitializedNewAndTarget,
- frameBuilder::isAssignableAndInitialized));
- frameBuilder.storeLocal(var, pop);
- return;
- case INT:
- frameBuilder.checkIsAssignable(
- pop, dexItemFactory.intType, frameBuilder::isAssignableAndInitialized);
- frameBuilder.storeLocal(var, FrameType.initialized(dexItemFactory.intType));
- return;
- case FLOAT:
- frameBuilder.checkIsAssignable(
- pop, dexItemFactory.floatType, frameBuilder::isAssignableAndInitialized);
- frameBuilder.storeLocal(var, FrameType.initialized(dexItemFactory.floatType));
- return;
- case LONG:
- frameBuilder.checkIsAssignable(
- pop, dexItemFactory.longType, frameBuilder::isAssignableAndInitialized);
- frameBuilder.storeLocal(var, FrameType.longType());
- frameBuilder.storeLocal(var + 1, FrameType.longType());
- return;
- case DOUBLE:
- frameBuilder.checkIsAssignable(
- pop, dexItemFactory.doubleType, frameBuilder::isAssignableAndInitialized);
- frameBuilder.storeLocal(var, FrameType.doubleType());
- frameBuilder.storeLocal(var + 1, FrameType.doubleType());
- return;
- default:
- throw new Unreachable("Unexpected type " + type);
- }
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
index 44bb2c9..3c3f06c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -172,17 +171,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., index/key →
- // ...
- frameBuilder.popInitialized(dexItemFactory.intType);
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
index 126c0ad..c7bc17e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.CfCompareHelper;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -100,19 +99,6 @@
}
@Override
- public void evaluate(
- CfFrameVerificationHelper frameBuilder,
- DexMethod context,
- AppView<?> appView,
- DexItemFactory dexItemFactory) {
- // ..., objectref →
- // objectref
- frameBuilder.popInitialized(dexItemFactory.throwableType);
- // The exception edges are verified in CfCode since this is a throwing instruction.
- frameBuilder.setNoFrame();
- }
-
- @Override
public CfFrameState evaluate(
CfFrameState frame,
AppView<?> appView,
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/BaseFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/BaseFrameType.java
new file mode 100644
index 0000000..ce9f818
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/BaseFrameType.java
@@ -0,0 +1,194 @@
+// 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.code.frame;
+
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+
+public abstract class BaseFrameType implements FrameType {
+
+ @Override
+ public boolean isBoolean() {
+ return false;
+ }
+
+ @Override
+ public boolean isByte() {
+ return false;
+ }
+
+ @Override
+ public boolean isChar() {
+ return false;
+ }
+
+ @Override
+ public boolean isDouble() {
+ return false;
+ }
+
+ @Override
+ public boolean isFloat() {
+ return false;
+ }
+
+ @Override
+ public boolean isInt() {
+ return false;
+ }
+
+ @Override
+ public boolean isLong() {
+ return false;
+ }
+
+ @Override
+ public boolean isShort() {
+ return false;
+ }
+
+ @Override
+ public boolean isNullType() {
+ return false;
+ }
+
+ @Override
+ public boolean isObject() {
+ return false;
+ }
+
+ @Override
+ public DexType getObjectType(DexType context) {
+ assert false : "Unexpected use of getObjectType() for non-object FrameType";
+ return null;
+ }
+
+ @Override
+ public boolean isPrecise() {
+ assert isOneWord() || isTwoWord();
+ return false;
+ }
+
+ @Override
+ public PreciseFrameType asPrecise() {
+ assert isOneWord() || isTwoWord();
+ return null;
+ }
+
+ @Override
+ public boolean isPrimitive() {
+ return false;
+ }
+
+ @Override
+ public PrimitiveFrameType asPrimitive() {
+ return null;
+ }
+
+ @Override
+ public final boolean isSingle() {
+ return !isWide();
+ }
+
+ @Override
+ public SingleFrameType asSingle() {
+ return null;
+ }
+
+ @Override
+ public SinglePrimitiveFrameType asSinglePrimitive() {
+ return null;
+ }
+
+ @Override
+ public InitializedReferenceFrameType asInitializedReferenceType() {
+ return null;
+ }
+
+ @Override
+ public boolean isWide() {
+ return false;
+ }
+
+ @Override
+ public WideFrameType asWide() {
+ return null;
+ }
+
+ @Override
+ public int getWidth() {
+ assert isSingle();
+ return 1;
+ }
+
+ @Override
+ public boolean isUninitializedNew() {
+ return false;
+ }
+
+ @Override
+ public UninitializedNew asUninitializedNew() {
+ return null;
+ }
+
+ @Override
+ public boolean isUninitialized() {
+ return false;
+ }
+
+ @Override
+ public UninitializedFrameType asUninitialized() {
+ return null;
+ }
+
+ @Override
+ public CfLabel getUninitializedLabel() {
+ return null;
+ }
+
+ @Override
+ public boolean isUninitializedThis() {
+ return false;
+ }
+
+ @Override
+ public UninitializedThis asUninitializedThis() {
+ return null;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return false;
+ }
+
+ @Override
+ public DexType getInitializedType(DexItemFactory dexItemFactory) {
+ return null;
+ }
+
+ @Override
+ public DexType getUninitializedNewType() {
+ return null;
+ }
+
+ @Override
+ public boolean isOneWord() {
+ return false;
+ }
+
+ @Override
+ public boolean isTwoWord() {
+ return false;
+ }
+
+ BaseFrameType() {}
+
+ @Override
+ public abstract boolean equals(Object obj);
+
+ @Override
+ public abstract int hashCode();
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/BooleanFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/BooleanFrameType.java
new file mode 100644
index 0000000..faca255
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/BooleanFrameType.java
@@ -0,0 +1,43 @@
+// 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.code.frame;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+
+public class BooleanFrameType extends SinglePrimitiveFrameType {
+
+ static final BooleanFrameType SINGLETON = new BooleanFrameType();
+
+ private BooleanFrameType() {}
+
+ @Override
+ public DexType getInitializedType(DexItemFactory dexItemFactory) {
+ return dexItemFactory.booleanType;
+ }
+
+ @Override
+ public String getTypeName() {
+ return "boolean";
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ throw new Unreachable("Unexpected value type: " + this);
+ }
+
+ @Override
+ public boolean hasIntVerificationType() {
+ return true;
+ }
+
+ @Override
+ public boolean isBoolean() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/ByteFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/ByteFrameType.java
new file mode 100644
index 0000000..c55f98f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/ByteFrameType.java
@@ -0,0 +1,43 @@
+// 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.code.frame;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+
+public class ByteFrameType extends SinglePrimitiveFrameType {
+
+ static final ByteFrameType SINGLETON = new ByteFrameType();
+
+ private ByteFrameType() {}
+
+ @Override
+ public DexType getInitializedType(DexItemFactory dexItemFactory) {
+ return dexItemFactory.byteType;
+ }
+
+ @Override
+ public String getTypeName() {
+ return "byte";
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ throw new Unreachable("Unexpected value type: " + this);
+ }
+
+ @Override
+ public boolean hasIntVerificationType() {
+ return true;
+ }
+
+ @Override
+ public boolean isByte() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/CharFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/CharFrameType.java
new file mode 100644
index 0000000..99fadc1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/CharFrameType.java
@@ -0,0 +1,43 @@
+// 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.code.frame;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+
+public class CharFrameType extends SinglePrimitiveFrameType {
+
+ static final CharFrameType SINGLETON = new CharFrameType();
+
+ private CharFrameType() {}
+
+ @Override
+ public DexType getInitializedType(DexItemFactory dexItemFactory) {
+ return dexItemFactory.charType;
+ }
+
+ @Override
+ public String getTypeName() {
+ return "char";
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ throw new Unreachable("Unexpected value type: " + this);
+ }
+
+ @Override
+ public boolean hasIntVerificationType() {
+ return true;
+ }
+
+ @Override
+ public boolean isChar() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/DoubleFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/DoubleFrameType.java
new file mode 100644
index 0000000..93c0687
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/DoubleFrameType.java
@@ -0,0 +1,38 @@
+// 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.code.frame;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class DoubleFrameType extends WidePrimitiveFrameType {
+
+ static final DoubleFrameType SINGLETON = new DoubleFrameType();
+
+ private DoubleFrameType() {}
+
+ @Override
+ public boolean isDouble() {
+ return true;
+ }
+
+ @Override
+ public DexType getInitializedType(DexItemFactory dexItemFactory) {
+ return dexItemFactory.doubleType;
+ }
+
+ @Override
+ public String getTypeName() {
+ return "double";
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ return Opcodes.DOUBLE;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/FloatFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/FloatFrameType.java
new file mode 100644
index 0000000..6789e2e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/FloatFrameType.java
@@ -0,0 +1,38 @@
+// 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.code.frame;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class FloatFrameType extends SinglePrimitiveFrameType {
+
+ static final FloatFrameType SINGLETON = new FloatFrameType();
+
+ private FloatFrameType() {}
+
+ @Override
+ public DexType getInitializedType(DexItemFactory dexItemFactory) {
+ return dexItemFactory.floatType;
+ }
+
+ @Override
+ public String getTypeName() {
+ return "float";
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ return Opcodes.FLOAT;
+ }
+
+ @Override
+ public boolean isFloat() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java
new file mode 100644
index 0000000..6522c7e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/FrameType.java
@@ -0,0 +1,198 @@
+// 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.code.frame;
+
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.ir.code.MemberType;
+import com.android.tools.r8.ir.code.NumericType;
+import com.android.tools.r8.naming.NamingLens;
+import java.util.function.Function;
+
+public interface FrameType {
+
+ static BooleanFrameType booleanType() {
+ return BooleanFrameType.SINGLETON;
+ }
+
+ static ByteFrameType byteType() {
+ return ByteFrameType.SINGLETON;
+ }
+
+ static CharFrameType charType() {
+ return CharFrameType.SINGLETON;
+ }
+
+ static DoubleFrameType doubleType() {
+ return DoubleFrameType.SINGLETON;
+ }
+
+ static FloatFrameType floatType() {
+ return FloatFrameType.SINGLETON;
+ }
+
+ static IntFrameType intType() {
+ return IntFrameType.SINGLETON;
+ }
+
+ static LongFrameType longType() {
+ return LongFrameType.SINGLETON;
+ }
+
+ static ShortFrameType shortType() {
+ return ShortFrameType.SINGLETON;
+ }
+
+ static InitializedFrameType initialized(DexType type) {
+ if (type.isPrimitiveType()) {
+ return primitive(type);
+ }
+ return new InitializedReferenceFrameType(type);
+ }
+
+ static PrimitiveFrameType primitive(DexType type) {
+ assert type.isPrimitiveType();
+ char c = (char) type.getDescriptor().content[0];
+ switch (c) {
+ case 'Z':
+ return booleanType();
+ case 'B':
+ return byteType();
+ case 'C':
+ return charType();
+ case 'D':
+ return doubleType();
+ case 'F':
+ return floatType();
+ case 'I':
+ return intType();
+ case 'J':
+ return longType();
+ case 'S':
+ return shortType();
+ default:
+ throw new Unreachable("Unexpected primitive type: " + type.getTypeName());
+ }
+ }
+
+ static UninitializedNew uninitializedNew(CfLabel label, DexType typeToInitialize) {
+ return new UninitializedNew(label, typeToInitialize);
+ }
+
+ static UninitializedThis uninitializedThis() {
+ return UninitializedThis.SINGLETON;
+ }
+
+ static OneWord oneWord() {
+ return OneWord.SINGLETON;
+ }
+
+ static TwoWord twoWord() {
+ return TwoWord.SINGLETON;
+ }
+
+ static PrimitiveFrameType fromNumericType(NumericType numericType, DexItemFactory factory) {
+ return FrameType.primitive(numericType.toDexType(factory));
+ }
+
+ static InitializedFrameType fromPreciseMemberType(MemberType memberType, DexItemFactory factory) {
+ assert memberType.isPrecise();
+ switch (memberType) {
+ case OBJECT:
+ return FrameType.initialized(factory.objectType);
+ case BOOLEAN_OR_BYTE:
+ case CHAR:
+ case SHORT:
+ case INT:
+ return intType();
+ case FLOAT:
+ return floatType();
+ case LONG:
+ return longType();
+ case DOUBLE:
+ return doubleType();
+ default:
+ throw new Unreachable("Unexpected MemberType: " + memberType);
+ }
+ }
+
+ DexType getInitializedType(DexItemFactory dexItemFactory);
+
+ DexType getObjectType(DexType context);
+
+ Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens);
+
+ CfLabel getUninitializedLabel();
+
+ DexType getUninitializedNewType();
+
+ int getWidth();
+
+ boolean isBoolean();
+
+ boolean isByte();
+
+ boolean isChar();
+
+ boolean isDouble();
+
+ boolean isFloat();
+
+ boolean isInitialized();
+
+ InitializedReferenceFrameType asInitializedReferenceType();
+
+ boolean isInt();
+
+ boolean isLong();
+
+ boolean isNullType();
+
+ boolean isObject();
+
+ boolean isOneWord();
+
+ boolean isPrecise();
+
+ PreciseFrameType asPrecise();
+
+ boolean isPrimitive();
+
+ PrimitiveFrameType asPrimitive();
+
+ boolean isShort();
+
+ boolean isSingle();
+
+ SingleFrameType asSingle();
+
+ SinglePrimitiveFrameType asSinglePrimitive();
+
+ boolean isTwoWord();
+
+ boolean isUninitialized();
+
+ UninitializedFrameType asUninitialized();
+
+ boolean isUninitializedNew();
+
+ UninitializedNew asUninitializedNew();
+
+ boolean isUninitializedThis();
+
+ UninitializedThis asUninitializedThis();
+
+ boolean isWide();
+
+ WideFrameType asWide();
+
+ default FrameType map(Function<DexType, DexType> fn) {
+ assert !isPrecise();
+ return this;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/InitializedFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/InitializedFrameType.java
new file mode 100644
index 0000000..f2a3d21
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/InitializedFrameType.java
@@ -0,0 +1,7 @@
+// 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.code.frame;
+
+public interface InitializedFrameType extends PreciseFrameType {}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/InitializedReferenceFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/InitializedReferenceFrameType.java
new file mode 100644
index 0000000..c2a2152
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/InitializedReferenceFrameType.java
@@ -0,0 +1,147 @@
+// 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.code.frame;
+
+import com.android.tools.r8.errors.Unimplemented;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class InitializedReferenceFrameType extends BaseFrameType
+ implements InitializedFrameType, SingleFrameType {
+
+ private final DexType type;
+
+ public InitializedReferenceFrameType(DexType type) {
+ assert type != null;
+ assert type.isReferenceType();
+ this.type = type;
+ }
+
+ @Override
+ public boolean isPrecise() {
+ return true;
+ }
+
+ @Override
+ public PreciseFrameType asPrecise() {
+ return this;
+ }
+
+ @Override
+ public InitializedReferenceFrameType asInitializedReferenceType() {
+ return this;
+ }
+
+ @Override
+ public SingleFrameType join(SingleFrameType frameType) {
+ if (equals(frameType)) {
+ return this;
+ }
+ if (frameType.isOneWord() || frameType.isPrimitive() || frameType.isUninitialized()) {
+ return FrameType.oneWord();
+ }
+ DexType otherType = frameType.asInitializedReferenceType().getInitializedType();
+ assert type != otherType;
+ assert type.isReferenceType();
+ if (isNullType()) {
+ return otherType.isReferenceType() ? frameType : FrameType.oneWord();
+ }
+ if (frameType.isNullType()) {
+ return this;
+ }
+ assert type.isArrayType() || type.isClassType();
+ assert otherType.isArrayType() || otherType.isClassType();
+ // TODO(b/214496607): Implement join of different reference types using class hierarchy.
+ throw new Unimplemented();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ InitializedReferenceFrameType initializedType = (InitializedReferenceFrameType) obj;
+ return type == initializedType.type;
+ }
+
+ @Override
+ public int hashCode() {
+ return type.hashCode();
+ }
+
+ @Override
+ public String toString() {
+ return "Initialized(" + type.toString() + ")";
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ DexType rewrittenType = graphLens.lookupType(type);
+ if (rewrittenType == DexItemFactory.nullValueType) {
+ return Opcodes.NULL;
+ }
+ switch (rewrittenType.toShorty()) {
+ case 'L':
+ return namingLens.lookupInternalName(rewrittenType);
+ case 'I':
+ return Opcodes.INTEGER;
+ case 'F':
+ return Opcodes.FLOAT;
+ case 'J':
+ return Opcodes.LONG;
+ case 'D':
+ return Opcodes.DOUBLE;
+ default:
+ throw new Unreachable("Unexpected value type: " + rewrittenType);
+ }
+ }
+
+ @Override
+ public SingleFrameType asSingle() {
+ return this;
+ }
+
+ @Override
+ public boolean isWide() {
+ return false;
+ }
+
+ @Override
+ public boolean isInitialized() {
+ return true;
+ }
+
+ public DexType getInitializedType() {
+ return type;
+ }
+
+ @Override
+ public DexType getInitializedType(DexItemFactory dexItemFactory) {
+ return getInitializedType();
+ }
+
+ @Override
+ public boolean isNullType() {
+ return type.isNullValueType();
+ }
+
+ @Override
+ public boolean isObject() {
+ return type.isReferenceType();
+ }
+
+ @Override
+ public DexType getObjectType(DexType context) {
+ assert isObject() : "Unexpected use of getObjectType() for non-object FrameType";
+ return type;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/IntFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/IntFrameType.java
new file mode 100644
index 0000000..23fd119
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/IntFrameType.java
@@ -0,0 +1,43 @@
+// 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.code.frame;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class IntFrameType extends SinglePrimitiveFrameType {
+
+ static final IntFrameType SINGLETON = new IntFrameType();
+
+ private IntFrameType() {}
+
+ @Override
+ public DexType getInitializedType(DexItemFactory dexItemFactory) {
+ return dexItemFactory.intType;
+ }
+
+ @Override
+ public String getTypeName() {
+ return "int";
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ return Opcodes.INTEGER;
+ }
+
+ @Override
+ public boolean hasIntVerificationType() {
+ return true;
+ }
+
+ @Override
+ public boolean isInt() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/LongFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/LongFrameType.java
new file mode 100644
index 0000000..1fb59c7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/LongFrameType.java
@@ -0,0 +1,38 @@
+// 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.code.frame;
+
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class LongFrameType extends WidePrimitiveFrameType {
+
+ static final LongFrameType SINGLETON = new LongFrameType();
+
+ private LongFrameType() {}
+
+ @Override
+ public boolean isLong() {
+ return true;
+ }
+
+ @Override
+ public DexType getInitializedType(DexItemFactory dexItemFactory) {
+ return dexItemFactory.longType;
+ }
+
+ @Override
+ public String getTypeName() {
+ return "long";
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ return Opcodes.LONG;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/OneWord.java b/src/main/java/com/android/tools/r8/cf/code/frame/OneWord.java
new file mode 100644
index 0000000..9ac5082
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/OneWord.java
@@ -0,0 +1,41 @@
+// 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.code.frame;
+
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class OneWord extends SingletonFrameType implements SingleFrameType {
+
+ static final OneWord SINGLETON = new OneWord();
+
+ private OneWord() {}
+
+ @Override
+ public boolean isOneWord() {
+ return true;
+ }
+
+ @Override
+ public SingleFrameType asSingle() {
+ return this;
+ }
+
+ @Override
+ public SingleFrameType join(SingleFrameType frameType) {
+ return this;
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ return Opcodes.TOP;
+ }
+
+ @Override
+ public String toString() {
+ return "oneword";
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/PreciseFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/PreciseFrameType.java
new file mode 100644
index 0000000..aa105e0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/PreciseFrameType.java
@@ -0,0 +1,32 @@
+// 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.code.frame;
+
+import com.android.tools.r8.graph.DexType;
+import java.util.function.Function;
+
+public interface PreciseFrameType extends FrameType {
+
+ @Override
+ default PreciseFrameType map(Function<DexType, DexType> fn) {
+ if (isObject()) {
+ if (isInitialized()) {
+ DexType type = asInitializedReferenceType().getInitializedType();
+ DexType newType = fn.apply(type);
+ if (type != newType) {
+ return FrameType.initialized(newType);
+ }
+ }
+ if (isUninitializedNew()) {
+ DexType type = getUninitializedNewType();
+ DexType newType = fn.apply(type);
+ if (type != newType) {
+ return FrameType.uninitializedNew(getUninitializedLabel(), newType);
+ }
+ }
+ }
+ return this;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/PrimitiveFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/PrimitiveFrameType.java
index 2db1925..446261a 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/PrimitiveFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/PrimitiveFrameType.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.cf.code.frame;
-public interface PrimitiveFrameType {
+public interface PrimitiveFrameType extends InitializedFrameType {
String getTypeName();
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/ShortFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/ShortFrameType.java
new file mode 100644
index 0000000..0b64a52
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/ShortFrameType.java
@@ -0,0 +1,43 @@
+// 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.code.frame;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+
+public class ShortFrameType extends SinglePrimitiveFrameType {
+
+ static final ShortFrameType SINGLETON = new ShortFrameType();
+
+ private ShortFrameType() {}
+
+ @Override
+ public DexType getInitializedType(DexItemFactory dexItemFactory) {
+ return dexItemFactory.shortType;
+ }
+
+ @Override
+ public String getTypeName() {
+ return "short";
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ throw new Unreachable("Unexpected value type: " + this);
+ }
+
+ @Override
+ public boolean hasIntVerificationType() {
+ return true;
+ }
+
+ @Override
+ public boolean isShort() {
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/SingleFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/SingleFrameType.java
index ce215b6..657d493 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/SingleFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/SingleFrameType.java
@@ -4,37 +4,8 @@
package com.android.tools.r8.cf.code.frame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
-import com.android.tools.r8.cf.code.CfFrame.SingleInitializedType;
-import com.android.tools.r8.cf.code.CfFrame.SinglePrimitiveFrameType;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexType;
-public interface SingleFrameType {
-
- FrameType asFrameType();
-
- boolean isInitialized();
-
- DexType getInitializedType(DexItemFactory dexItemFactory);
-
- boolean isInt();
-
- SingleInitializedType asSingleInitializedType();
-
- boolean isNullType();
-
- boolean isOneWord();
-
- boolean isPrimitive();
-
- SinglePrimitiveFrameType asSinglePrimitive();
-
- boolean isUninitializedNew();
-
- DexType getUninitializedNewType();
-
- boolean isUninitializedObject();
+public interface SingleFrameType extends FrameType {
SingleFrameType join(SingleFrameType frameType);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/SinglePrimitiveFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/SinglePrimitiveFrameType.java
new file mode 100644
index 0000000..69ba4b6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/SinglePrimitiveFrameType.java
@@ -0,0 +1,66 @@
+// 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.code.frame;
+
+public abstract class SinglePrimitiveFrameType extends SingletonFrameType
+ implements PrimitiveFrameType, SingleFrameType {
+
+ public boolean hasIntVerificationType() {
+ return false;
+ }
+
+ @Override
+ public final boolean isInitialized() {
+ return true;
+ }
+
+ @Override
+ public final boolean isPrecise() {
+ return true;
+ }
+
+ @Override
+ public PreciseFrameType asPrecise() {
+ return this;
+ }
+
+ @Override
+ public final boolean isPrimitive() {
+ return true;
+ }
+
+ @Override
+ public PrimitiveFrameType asPrimitive() {
+ return this;
+ }
+
+ @Override
+ public final SingleFrameType asSingle() {
+ return this;
+ }
+
+ @Override
+ public final SinglePrimitiveFrameType asSinglePrimitive() {
+ return this;
+ }
+
+ @Override
+ public final SingleFrameType join(SingleFrameType frameType) {
+ if (this == frameType) {
+ return this;
+ }
+ if (hasIntVerificationType()
+ && frameType.isPrimitive()
+ && frameType.asSinglePrimitive().hasIntVerificationType()) {
+ return FrameType.intType();
+ }
+ return FrameType.oneWord();
+ }
+
+ @Override
+ public final String toString() {
+ return getTypeName();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/SingletonFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/SingletonFrameType.java
new file mode 100644
index 0000000..a8759af
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/SingletonFrameType.java
@@ -0,0 +1,18 @@
+// 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.code.frame;
+
+public abstract class SingletonFrameType extends BaseFrameType {
+
+ @Override
+ public final boolean equals(Object obj) {
+ return this == obj;
+ }
+
+ @Override
+ public final int hashCode() {
+ return System.identityHashCode(this);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/TwoWord.java b/src/main/java/com/android/tools/r8/cf/code/frame/TwoWord.java
new file mode 100644
index 0000000..23a4ca1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/TwoWord.java
@@ -0,0 +1,52 @@
+// 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.code.frame;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+
+public class TwoWord extends SingletonFrameType implements WideFrameType {
+
+ static final TwoWord SINGLETON = new TwoWord();
+
+ private TwoWord() {}
+
+ @Override
+ public boolean isTwoWord() {
+ return true;
+ }
+
+ @Override
+ public boolean isWide() {
+ return true;
+ }
+
+ @Override
+ public WideFrameType asWide() {
+ return this;
+ }
+
+ @Override
+ public int getWidth() {
+ return 2;
+ }
+
+ @Override
+ public WideFrameType join(WideFrameType frameType) {
+ // The join of wide with one of {double, long, wide} is wide.
+ return this;
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ throw new Unreachable("Should only be used for verification");
+ }
+
+ @Override
+ public String toString() {
+ return "twoword";
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedFrameType.java
new file mode 100644
index 0000000..a31453d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedFrameType.java
@@ -0,0 +1,39 @@
+// 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.code.frame;
+
+public abstract class UninitializedFrameType extends BaseFrameType
+ implements PreciseFrameType, SingleFrameType {
+
+ @Override
+ public boolean isObject() {
+ return true;
+ }
+
+ @Override
+ public boolean isPrecise() {
+ return true;
+ }
+
+ @Override
+ public PreciseFrameType asPrecise() {
+ return this;
+ }
+
+ @Override
+ public SingleFrameType asSingle() {
+ return this;
+ }
+
+ @Override
+ public boolean isUninitialized() {
+ return true;
+ }
+
+ @Override
+ public UninitializedFrameType asUninitialized() {
+ return this;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedNew.java b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedNew.java
new file mode 100644
index 0000000..03eff42
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedNew.java
@@ -0,0 +1,79 @@
+// 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.code.frame;
+
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import java.util.Objects;
+
+public class UninitializedNew extends UninitializedFrameType {
+
+ private final CfLabel label;
+ private final DexType type;
+
+ public UninitializedNew(CfLabel label, DexType type) {
+ this.label = label;
+ this.type = type;
+ }
+
+ @Override
+ public DexType getObjectType(DexType context) {
+ return type;
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ return label.getLabel();
+ }
+
+ @Override
+ public CfLabel getUninitializedLabel() {
+ return label;
+ }
+
+ @Override
+ public DexType getUninitializedNewType() {
+ return type;
+ }
+
+ @Override
+ public boolean isUninitializedNew() {
+ return true;
+ }
+
+ @Override
+ public UninitializedNew asUninitializedNew() {
+ return this;
+ }
+
+ @Override
+ public SingleFrameType join(SingleFrameType frameType) {
+ return equals(frameType) ? this : FrameType.oneWord();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ UninitializedNew uninitializedNew = (UninitializedNew) o;
+ return label == uninitializedNew.label && type == uninitializedNew.type;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(label, type);
+ }
+
+ @Override
+ public String toString() {
+ return "uninitialized new";
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedThis.java b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedThis.java
new file mode 100644
index 0000000..69d1ecb
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/UninitializedThis.java
@@ -0,0 +1,60 @@
+// Copyright (c) 2022, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.cf.code.frame;
+
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.naming.NamingLens;
+import org.objectweb.asm.Opcodes;
+
+public class UninitializedThis extends UninitializedFrameType {
+
+ static final UninitializedThis SINGLETON = new UninitializedThis();
+
+ private UninitializedThis() {}
+
+ @Override
+ public DexType getObjectType(DexType context) {
+ return context;
+ }
+
+ @Override
+ public Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ return Opcodes.UNINITIALIZED_THIS;
+ }
+
+ @Override
+ public boolean isUninitializedThis() {
+ return true;
+ }
+
+ @Override
+ public UninitializedThis asUninitializedThis() {
+ return this;
+ }
+
+ @Override
+ public SingleFrameType join(SingleFrameType frameType) {
+ if (this == frameType) {
+ return this;
+ }
+ return FrameType.oneWord();
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return this == obj;
+ }
+
+ @Override
+ public int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override
+ public String toString() {
+ return "uninitialized this";
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/WideFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/WideFrameType.java
index 027c2537..d780cf4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/frame/WideFrameType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/WideFrameType.java
@@ -4,17 +4,8 @@
package com.android.tools.r8.cf.code.frame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
-public interface WideFrameType {
-
- FrameType asFrameType();
-
- boolean isDouble();
-
- boolean isLong();
-
- boolean isTwoWord();
+public interface WideFrameType extends FrameType {
default boolean lessThanOrEqualTo(WideFrameType frameType) {
return join(frameType) == frameType;
diff --git a/src/main/java/com/android/tools/r8/cf/code/frame/WidePrimitiveFrameType.java b/src/main/java/com/android/tools/r8/cf/code/frame/WidePrimitiveFrameType.java
new file mode 100644
index 0000000..11f7b75
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/cf/code/frame/WidePrimitiveFrameType.java
@@ -0,0 +1,59 @@
+// 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.code.frame;
+
+public abstract class WidePrimitiveFrameType extends SingletonFrameType
+ implements PrimitiveFrameType, WideFrameType {
+
+ @Override
+ public boolean isInitialized() {
+ return true;
+ }
+
+ @Override
+ public boolean isPrecise() {
+ return true;
+ }
+
+ @Override
+ public PreciseFrameType asPrecise() {
+ return this;
+ }
+
+ @Override
+ public boolean isPrimitive() {
+ return true;
+ }
+
+ @Override
+ public PrimitiveFrameType asPrimitive() {
+ return this;
+ }
+
+ @Override
+ public boolean isWide() {
+ return true;
+ }
+
+ @Override
+ public WideFrameType asWide() {
+ return this;
+ }
+
+ @Override
+ public int getWidth() {
+ return 2;
+ }
+
+ @Override
+ public WideFrameType join(WideFrameType frameType) {
+ return this == frameType ? this : FrameType.twoWord();
+ }
+
+ @Override
+ public final String toString() {
+ return getTypeName();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index d2cff23..95358b2 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -727,6 +727,18 @@
options.itemFactory));
}
+ if (clazz.isNestHost()) {
+ annotations.add(
+ DexAnnotation.createNestMembersAnnotation(
+ clazz.getNestMembersClassAttributes(), options.itemFactory));
+ }
+
+ if (clazz.isNestMember()) {
+ annotations.add(
+ DexAnnotation.createNestHostAnnotation(
+ clazz.getNestHostClassAttribute(), options.itemFactory));
+ }
+
if (!annotations.isEmpty()) {
// Append the annotations to annotations array of the class.
DexAnnotation[] copy =
diff --git a/src/main/java/com/android/tools/r8/dex/DexParser.java b/src/main/java/com/android/tools/r8/dex/DexParser.java
index 8705bb4..10132f3 100644
--- a/src/main/java/com/android/tools/r8/dex/DexParser.java
+++ b/src/main/java/com/android/tools/r8/dex/DexParser.java
@@ -61,6 +61,8 @@
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.NestHostClassAttribute;
+import com.android.tools.r8.graph.NestMemberClassAttribute;
import com.android.tools.r8.graph.OffsetToObjectMapping;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.logging.Log;
@@ -855,8 +857,8 @@
superclass,
typeListAt(interfacesOffsets[i]),
source,
- null,
- Collections.emptyList(),
+ attrs.nestHostAttribute,
+ attrs.nestMembersAttribute,
attrs.getEnclosingMethodAttribute(),
attrs.getInnerClasses(),
attrs.classSignature,
@@ -1423,6 +1425,8 @@
private List<InnerClassAttribute> innerClasses = null;
private List<DexAnnotation> lazyAnnotations = null;
private ClassSignature classSignature = ClassSignature.noSignature();
+ private NestHostClassAttribute nestHostAttribute;
+ private List<NestMemberClassAttribute> nestMembersAttribute = Collections.emptyList();
public DexAnnotationSet getAnnotations() {
if (lazyAnnotations != null) {
@@ -1486,6 +1490,20 @@
classSignature =
GenericSignature.parseClassSignature(
type.getName(), signature, origin, factory, options.reporter);
+ } else if (DexAnnotation.isNestHostAnnotation(annotation, factory)) {
+ ensureAnnotations(i);
+ nestHostAttribute =
+ new NestHostClassAttribute(
+ DexAnnotation.getNestHostFromAnnotation(annotation, factory));
+ } else if (DexAnnotation.isNestMembersAnnotation(annotation, factory)) {
+ ensureAnnotations(i);
+ List<DexType> members = DexAnnotation.getNestMembersFromAnnotation(annotation, factory);
+ if (members != null) {
+ nestMembersAttribute = new ArrayList<>(members.size());
+ for (DexType member : members) {
+ nestMembersAttribute.add(new NestMemberClassAttribute(member));
+ }
+ }
} else {
copyAnnotation(annotation);
}
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 321c775..42d0bcd 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfFrameVerificationHelper;
import com.android.tools.r8.cf.code.CfIinc;
import com.android.tools.r8.cf.code.CfInstruction;
@@ -18,6 +17,7 @@
import com.android.tools.r8.cf.code.CfPosition;
import com.android.tools.r8.cf.code.CfReturnVoid;
import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.dex.code.CfOrDexInstruction;
import com.android.tools.r8.dex.code.DexBase5Format;
import com.android.tools.r8.errors.InvalidDebugInfoException;
@@ -31,7 +31,6 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Position.SyntheticPosition;
import com.android.tools.r8.ir.conversion.CfSourceCode;
-import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.conversion.MethodConversionOptions.MutableMethodConversionOptions;
@@ -40,9 +39,12 @@
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.NamingLens;
+import com.android.tools.r8.optimize.interfaces.analysis.CfFrameState;
+import com.android.tools.r8.optimize.interfaces.analysis.ConcreteCfFrameState;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralItem;
@@ -950,60 +952,60 @@
return reportStackMapError(
CfCodeStackMapValidatingException.noFramesForMethodWithJumps(method, appView), appView);
}
- CfFrameVerificationHelper builder =
- new CfFrameVerificationHelper(
- appView, previousMethodSignature.getHolderType(), stateMap, tryCatchRanges, maxStack);
- for (CfTryCatch tryCatchRange : tryCatchRanges) {
- try {
- builder.checkTryCatchRange(tryCatchRange);
- } catch (CfCodeStackMapValidatingException ex) {
- return reportStackMapError(
- CfCodeStackMapValidatingException.invalidTryCatchRange(
- method, tryCatchRange, ex.getMessage(), appView),
- appView);
- }
+ CfFrameVerificationHelper helper =
+ new CfFrameVerificationHelper(appView, this, method, stateMap, tryCatchRanges);
+ CfCodeDiagnostics diagnostics = helper.checkTryCatchRanges();
+ if (diagnostics != null) {
+ return reportStackMapError(diagnostics, appView);
}
- if (stateMap.containsKey(null)) {
- assert !shouldComputeInitialFrame();
- builder.checkFrameAndSet(stateMap.get(null));
- } else if (shouldComputeInitialFrame()) {
- builder.checkFrameAndSet(
- computeInitialFrame(
- appView, previousMethodSignature, previousMethodSignatureIsInstance, protoChanges));
+ TraversalContinuation<CfCodeDiagnostics, CfFrameState> initialState =
+ computeInitialState(
+ appView, helper, method, previousMethodSignature, previousMethodSignatureIsInstance);
+ if (initialState.shouldBreak()) {
+ return reportStackMapError(initialState.asBreak().getValue(), appView);
}
+ CfFrameState state = initialState.asContinue().getValue();
for (int i = 0; i < instructions.size(); i++) {
CfInstruction instruction = instructions.get(i);
- try {
- // Check the exceptional edge prior to evaluating the instruction. The local state is stable
- // at this point as store operations are not throwing and the current stack does not
- // affect the exceptional transfer (the exception edge is always a singleton stack).
- if (instruction.canThrow()) {
- assert !instruction.isStore();
- builder.checkExceptionEdges();
- }
- if (instruction.isLabel()) {
- builder.seenLabel(instruction.asLabel());
- }
- instruction.evaluate(builder, previousMethodSignature, appView, appView.dexItemFactory());
- if (instruction.isJumpWithNormalTarget()) {
- CfInstruction fallthroughInstruction =
- (i + 1) < instructions.size() ? instructions.get(i + 1) : null;
- instruction.forEachNormalTarget(
- target -> {
- if (target != fallthroughInstruction) {
- assert target.isLabel();
- builder.checkTarget(target.asLabel());
- }
- },
- fallthroughInstruction);
- if (!instruction.asJump().hasFallthrough()) {
- builder.setNoFrame();
- }
- }
- } catch (CfCodeStackMapValidatingException ex) {
+ assert !state.isError();
+ // Check the exceptional edge prior to evaluating the instruction. The local state is stable
+ // at this point as store operations are not throwing and the current stack does not
+ // affect the exceptional transfer (the exception edge is always a singleton stack).
+ if (instruction.canThrow()) {
+ assert !instruction.isStore();
+ state = helper.checkExceptionEdges(state);
+ }
+ if (instruction.isLabel()) {
+ helper.seenLabel(instruction.asLabel());
+ }
+ state = instruction.evaluate(state, appView, helper, appView.dexItemFactory());
+ if (instruction.isJumpWithNormalTarget()) {
+ CfInstruction fallthroughInstruction =
+ (i + 1) < instructions.size() ? instructions.get(i + 1) : null;
+ TraversalContinuation<CfCodeDiagnostics, CfFrameState> traversalContinuation =
+ instruction.traverseNormalTargets(
+ (target, currentState) -> {
+ if (target != fallthroughInstruction) {
+ assert target.isLabel();
+ currentState = helper.checkTarget(currentState, target.asLabel());
+ }
+ return TraversalContinuation.doContinue(currentState);
+ },
+ fallthroughInstruction,
+ state);
+ state = traversalContinuation.asContinue().getValue();
+ }
+ TraversalContinuation<CfCodeDiagnostics, CfFrameState> traversalContinuation =
+ helper.computeStateForNextInstruction(instruction, i, state);
+ if (traversalContinuation.isContinue()) {
+ state = traversalContinuation.asContinue().getValue();
+ } else {
+ return reportStackMapError(traversalContinuation.asBreak().getValue(), appView);
+ }
+ if (state.isError()) {
return reportStackMapError(
CfCodeStackMapValidatingException.invalidStackMapForInstruction(
- method, i, instruction, ex.getMessage(), appView),
+ method, i, instruction, state.asError().getMessage(), appView),
appView);
}
}
@@ -1037,40 +1039,37 @@
throw new Unreachable("Instruction " + instruction + " should be in instructions");
}
- private boolean shouldComputeInitialFrame() {
- for (CfInstruction instruction : instructions) {
- if (instruction.isFrame()) {
- return false;
- } else if (!instruction.isLabel() && !instruction.isPosition()) {
- return true;
- }
- }
- // We should never see a method with only labels and positions.
- assert false;
- return true;
- }
-
- private CfFrame computeInitialFrame(
+ private TraversalContinuation<CfCodeDiagnostics, CfFrameState> computeInitialState(
AppView<?> appView,
- DexMethod method,
- boolean isInstance,
- RewrittenPrototypeDescription prototypeChanges) {
+ CfFrameVerificationHelper helper,
+ ProgramMethod method,
+ DexMethod previousMethodSignature,
+ boolean previousMethodSignatureIsInstance) {
DexItemFactory dexItemFactory = appView.dexItemFactory();
- CfFrame.Builder builder = CfFrame.builder();
- if (isInstance) {
- builder.appendLocal(
- method.isInstanceInitializer(dexItemFactory)
- || method.mustBeInlinedIntoInstanceInitializer(appView)
- || method.isHorizontallyMergedInstanceInitializer(dexItemFactory)
- ? FrameType.uninitializedThis()
- : FrameType.initialized(method.getHolderType()));
+ CfFrameState state = ConcreteCfFrameState.bottom();
+ int localIndex = 0;
+ if (previousMethodSignatureIsInstance) {
+ state =
+ state.storeLocal(
+ localIndex,
+ previousMethodSignature.isInstanceInitializer(dexItemFactory)
+ || previousMethodSignature.mustBeInlinedIntoInstanceInitializer(appView)
+ || previousMethodSignature.isHorizontallyMergedInstanceInitializer(
+ dexItemFactory)
+ ? FrameType.uninitializedThis()
+ : FrameType.initialized(previousMethodSignature.getHolderType()),
+ helper);
+ localIndex++;
}
- for (DexType parameter : method.getParameters()) {
- builder.appendLocal(FrameType.initialized(parameter));
+ for (DexType parameter : previousMethodSignature.getParameters()) {
+ state = state.storeLocal(localIndex, FrameType.initialized(parameter), helper);
+ localIndex += parameter.getRequiredRegisters();
}
- for (ExtraParameter extraParameter : prototypeChanges.getExtraParameters()) {
- builder.appendLocal(FrameType.initialized(extraParameter.getType(dexItemFactory)));
+ if (state.isError()) {
+ return TraversalContinuation.doBreak(
+ CfCodeStackMapValidatingException.invalidStackMapForInstruction(
+ method, 0, instructions.get(0), state.asError().getMessage(), appView));
}
- return builder.build();
+ return TraversalContinuation.doContinue(state);
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/CfCodeStackMapValidatingException.java b/src/main/java/com/android/tools/r8/graph/CfCodeStackMapValidatingException.java
index 4b417bf..cc3f47c 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCodeStackMapValidatingException.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCodeStackMapValidatingException.java
@@ -8,15 +8,7 @@
import com.android.tools.r8.cf.code.CfTryCatch;
import com.android.tools.r8.utils.StringUtils;
-public class CfCodeStackMapValidatingException extends RuntimeException {
-
- private CfCodeStackMapValidatingException(String message) {
- super(message);
- }
-
- public static CfCodeStackMapValidatingException error(String message) {
- return new CfCodeStackMapValidatingException(message);
- }
+public class CfCodeStackMapValidatingException {
public static CfCodeDiagnostics unexpectedStackMapFrame(
ProgramMethod method, AppView<?> appView) {
@@ -78,7 +70,7 @@
String detailMessage,
AppView<?> appView) {
StringBuilder sb =
- new StringBuilder("Invalid stack map table at ")
+ new StringBuilder("Invalid stack map table at instruction ")
.append(instructionIndex)
.append(": ")
.append(instruction)
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index 44ac005..c43d396 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -178,6 +178,14 @@
return annotation.annotation.type == factory.annotationMemberClasses;
}
+ public static boolean isNestHostAnnotation(DexAnnotation annotation, DexItemFactory factory) {
+ return annotation.annotation.type == factory.annotationNestHost;
+ }
+
+ public static boolean isNestMembersAnnotation(DexAnnotation annotation, DexItemFactory factory) {
+ return annotation.annotation.type == factory.annotationNestMembers;
+ }
+
public static DexAnnotation createInnerClassAnnotation(
DexString clazz, int access, DexItemFactory factory) {
return new DexAnnotation(
@@ -235,6 +243,29 @@
return types;
}
+ public static DexType getNestHostFromAnnotation(
+ DexAnnotation annotation, DexItemFactory factory) {
+ DexValue value = getSystemValueAnnotationValue(factory.annotationNestHost, annotation);
+ if (value == null) {
+ return null;
+ }
+ return value.asDexValueType().getValue();
+ }
+
+ public static List<DexType> getNestMembersFromAnnotation(
+ DexAnnotation annotation, DexItemFactory factory) {
+ DexValue value = getSystemValueAnnotationValue(factory.annotationNestMembers, annotation);
+ if (value == null) {
+ return null;
+ }
+ DexValueArray membersArray = value.asDexValueArray();
+ List<DexType> types = new ArrayList<>(membersArray.getValues().length);
+ for (DexValue elementValue : membersArray.getValues()) {
+ types.add(elementValue.asDexValueType().value);
+ }
+ return types;
+ }
+
public static DexAnnotation createSourceDebugExtensionAnnotation(DexValue value,
DexItemFactory factory) {
return new DexAnnotation(VISIBILITY_SYSTEM,
@@ -273,6 +304,24 @@
compressSignature(signature, factory));
}
+ public static DexAnnotation createNestHostAnnotation(
+ NestHostClassAttribute host, DexItemFactory factory) {
+ return createSystemValueAnnotation(
+ factory.annotationNestHost, factory, new DexValue.DexValueType(host.getNestHost()));
+ }
+
+ public static DexAnnotation createNestMembersAnnotation(
+ List<NestMemberClassAttribute> members, DexItemFactory factory) {
+ List<DexValueType> list = new ArrayList<>(members.size());
+ for (NestMemberClassAttribute member : members) {
+ list.add(new DexValue.DexValueType(member.getNestMember()));
+ }
+ return createSystemValueAnnotation(
+ factory.annotationNestMembers,
+ factory,
+ new DexValue.DexValueArray(list.toArray(DexValue.EMPTY_ARRAY)));
+ }
+
public static String getSignature(DexAnnotation signatureAnnotation) {
DexValueArray elements = signatureAnnotation.annotation.elements[0].value.asDexValueArray();
StringBuilder signature = new StringBuilder();
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 7c0e5d2..36f8d0f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -642,6 +642,10 @@
createStaticallyKnownType("Ldalvik/annotation/MethodParameters;");
public final DexType annotationSignature =
createStaticallyKnownType(dalvikAnnotationSignatureString);
+ public final DexType annotationNestHost =
+ createStaticallyKnownType("Ldalvik/annotation/NestHost;");
+ public final DexType annotationNestMembers =
+ createStaticallyKnownType("Ldalvik/annotation/NestMembers;");
public final DexType annotationSourceDebugExtension =
createStaticallyKnownType("Ldalvik/annotation/SourceDebugExtension;");
public final DexType annotationThrows = createStaticallyKnownType("Ldalvik/annotation/Throws;");
diff --git a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
index 6797285..d18e823 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyCfCode.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-
import com.android.tools.r8.cf.code.CfArithmeticBinop;
import com.android.tools.r8.cf.code.CfArrayLength;
import com.android.tools.r8.cf.code.CfArrayLoad;
@@ -19,7 +18,6 @@
import com.android.tools.r8.cf.code.CfConstString;
import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfGoto;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfIfCmp;
@@ -47,6 +45,9 @@
import com.android.tools.r8.cf.code.CfSwitch;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.cf.code.frame.PreciseFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedNew;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
@@ -72,6 +73,8 @@
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Reporter;
+import com.android.tools.r8.utils.StringDiagnostic;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import it.unimi.dsi.fastutil.ints.IntArrayList;
@@ -452,12 +455,12 @@
for (Int2ObjectMap.Entry<FrameType> entry : frame.getLocals().int2ObjectEntrySet()) {
FrameType frameType = entry.getValue();
if (frameType.isUninitializedNew() && frameType.getUninitializedNewType() == null) {
- entry.setValue(fixupUninitializedNew(frameType));
+ entry.setValue(fixupUninitializedNew(frameType.asUninitializedNew()));
}
}
- for (FrameType frameType : frame.getStack()) {
+ for (PreciseFrameType frameType : frame.getStack()) {
if (frameType.isUninitializedNew() && frameType.getUninitializedNewType() == null) {
- builder.push(fixupUninitializedNew(frameType));
+ builder.push(fixupUninitializedNew(frameType.asUninitializedNew()));
} else {
builder.push(frameType);
}
@@ -466,7 +469,7 @@
}
}
- private FrameType fixupUninitializedNew(FrameType frameType) {
+ private UninitializedNew fixupUninitializedNew(UninitializedNew frameType) {
CfLabel label = frameType.getUninitializedLabel();
CfNew cfNew = labelToNewMap.get(label);
return cfNew != null ? FrameType.uninitializedNew(label, cfNew.getType()) : frameType;
@@ -490,7 +493,9 @@
assert frameType == Opcodes.F_NEW;
CfFrame.Builder builder = CfFrame.builder();
parseLocals(nLocals, localTypes, builder);
- parseStack(nStack, stackTypes, builder);
+ if (!parseStack(nStack, stackTypes, builder)) {
+ return;
+ }
if (builder.hasIncompleteUninitializedNew()) {
framesWithIncompleteUninitializedNew.add(instructions.size());
}
@@ -505,11 +510,20 @@
}
}
- private void parseStack(int nStack, Object[] stackTypes, CfFrame.Builder builder) {
+ private boolean parseStack(int nStack, Object[] stackTypes, CfFrame.Builder builder) {
builder.allocateStack(nStack);
for (int i = 0; i < nStack; i++) {
- builder.push(getFrameType(stackTypes[i], builder));
+ FrameType frameType = getFrameType(stackTypes[i], builder);
+ if (frameType.isPrecise()) {
+ builder.push(frameType.asPrecise());
+ } else {
+ Reporter reporter = application.options.reporter;
+ reporter.warning(
+ new StringDiagnostic("Unexpected frame with imprecise value on stack", origin));
+ return false;
+ }
}
+ return true;
}
private FrameType getFrameType(Object localType, CfFrame.Builder builder) {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java
index 464db91..25933dd 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java
@@ -35,7 +35,7 @@
return new ClassInstanceFieldsMergerImpl(appView.withClassHierarchy(), lensBuilder, group);
} else {
assert group.getInstanceFieldMap().isEmpty();
- appView.options().horizontalClassMergerOptions().isRestrictedToSynthetics();
+ assert appView.options().horizontalClassMergerOptions().isRestrictedToSynthetics();
return new ClassInstanceFieldsMerger() {
@Override
public void setClassIdField(DexEncodedField classIdField) {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
index be68650..2bd4d6e 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/IncompleteVirtuallyMergedMethodCode.java
@@ -5,7 +5,6 @@
package com.android.tools.r8.horizontalclassmerging;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfInstanceFieldRead;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
@@ -15,6 +14,7 @@
import com.android.tools.r8.cf.code.CfReturnVoid;
import com.android.tools.r8.cf.code.CfSwitch;
import com.android.tools.r8.cf.code.CfSwitch.Kind;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -23,6 +23,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.horizontalclassmerging.VirtualMethodMerger.SuperMethodReference;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.IterableUtils;
@@ -42,13 +43,13 @@
private final DexField classIdField;
private final Int2ReferenceSortedMap<DexMethod> mappedMethods;
private final DexMethod originalMethod;
- private final DexMethod superMethod;
+ private final SuperMethodReference superMethod;
public IncompleteVirtuallyMergedMethodCode(
DexField classIdField,
Int2ReferenceSortedMap<DexMethod> mappedMethods,
DexMethod originalMethod,
- DexMethod superMethod) {
+ SuperMethodReference superMethod) {
this.mappedMethods = mappedMethods;
this.classIdField = classIdField;
this.superMethod = superMethod;
@@ -136,7 +137,12 @@
fallthroughTarget =
lens.getNextMethodSignature(mappedMethods.get(mappedMethods.lastIntKey()));
} else {
- fallthroughTarget = lens.lookupInvokeSuper(superMethod, method).getReference();
+ DexMethod reboundFallthroughTarget =
+ lens.lookupInvokeSuper(superMethod.getReboundReference(), method).getReference();
+ fallthroughTarget =
+ reboundFallthroughTarget.withHolder(
+ lens.lookupClassType(superMethod.getReference().getHolderType()),
+ appView.dexItemFactory());
}
instructions.add(
new CfInvoke(Opcodes.INVOKESPECIAL, fallthroughTarget, method.getHolder().isInterface()));
@@ -167,8 +173,7 @@
for (int argumentIndex = 0;
argumentIndex < representative.getDefinition().getNumberOfArguments();
argumentIndex++) {
- FrameType frameType = FrameType.initialized(representative.getArgumentType(argumentIndex));
- builder.appendLocal(frameType);
+ builder.appendLocal(FrameType.initialized(representative.getArgumentType(argumentIndex)));
}
CfFrame frame = builder.build();
assert frame.getLocals().size() == localsSize;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index 6abb160..4e3227a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -27,17 +27,36 @@
public class VirtualMethodMerger {
+ static class SuperMethodReference {
+
+ DexMethod reference;
+ DexMethod reboundReference;
+
+ SuperMethodReference(DexMethod reference, DexMethod reboundReference) {
+ this.reference = reference;
+ this.reboundReference = reboundReference;
+ }
+
+ public DexMethod getReference() {
+ return reference;
+ }
+
+ public DexMethod getReboundReference() {
+ return reboundReference;
+ }
+ }
+
private final AppView<? extends AppInfoWithClassHierarchy> appView;
private final DexItemFactory dexItemFactory;
private final MergeGroup group;
private final List<ProgramMethod> methods;
- private final DexMethod superMethod;
+ private final SuperMethodReference superMethod;
public VirtualMethodMerger(
AppView<? extends AppInfoWithClassHierarchy> appView,
MergeGroup group,
List<ProgramMethod> methods,
- DexMethod superMethod) {
+ SuperMethodReference superMethod) {
this.appView = appView;
this.dexItemFactory = appView.dexItemFactory();
this.group = group;
@@ -54,7 +73,7 @@
}
/** Get the super method handle if this method overrides a parent method. */
- private DexMethod superMethod(
+ private SuperMethodReference superMethod(
AppView<? extends AppInfoWithClassHierarchy> appView, MergeGroup group) {
DexMethod template = methods.iterator().next().getReference();
SingleResolutionResult<?> resolutionResult =
@@ -66,20 +85,22 @@
// If there is no super method or the method is abstract it should not be called.
return null;
}
- if (resolutionResult.getResolvedHolder().isInterface()) {
- // Ensure that invoke virtual isn't called on an interface method.
- return resolutionResult
- .getResolvedMethod()
- .getReference()
- .withHolder(group.getSuperType(), appView.dexItemFactory());
- }
- return resolutionResult.getResolvedMethod().getReference();
+ DexMethod reboundReference = resolutionResult.getResolvedMethod().getReference();
+ DexMethod reference =
+ resolutionResult.getResolvedHolder().isInterface()
+ ? resolutionResult
+ .getResolvedMethod()
+ .getReference()
+ .withHolder(group.getSuperType(), appView.dexItemFactory())
+ : reboundReference;
+ return new SuperMethodReference(reference, reboundReference);
}
public VirtualMethodMerger build(
AppView<? extends AppInfoWithClassHierarchy> appView, MergeGroup group) {
// If not all the classes are in the merge group, find the fallback super method to call.
- DexMethod superMethod = methods.size() < group.size() ? superMethod(appView, group) : null;
+ SuperMethodReference superMethod =
+ methods.size() < group.size() ? superMethod(appView, group) : null;
return new VirtualMethodMerger(appView, group, methods, superMethod);
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckSyntheticClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckSyntheticClasses.java
index 4d2554a..c9c3569 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckSyntheticClasses.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/CheckSyntheticClasses.java
@@ -25,7 +25,8 @@
if (!options.isSyntheticMergingEnabled() && syntheticItems.isSyntheticClass(clazz)) {
return false;
}
- if (options.isRestrictedToSynthetics() && !syntheticItems.isSyntheticClass(clazz)) {
+ if (options.isRestrictedToSynthetics()
+ && !syntheticItems.isSyntheticClassEligibleForMerging(clazz)) {
return false;
}
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/MemberType.java b/src/main/java/com/android/tools/r8/ir/code/MemberType.java
index fe1048a..c85a687 100644
--- a/src/main/java/com/android/tools/r8/ir/code/MemberType.java
+++ b/src/main/java/com/android/tools/r8/ir/code/MemberType.java
@@ -75,6 +75,7 @@
public static MemberType fromTypeDescriptorChar(char descriptor) {
switch (descriptor) {
case 'L':
+ case 'N':
case '[':
return MemberType.OBJECT;
case 'Z':
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
index 13c1982..e6228f7 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfBuilder.java
@@ -13,12 +13,14 @@
import com.android.tools.r8.cf.TypeVerificationHelper.ThisInstanceInfo;
import com.android.tools.r8.cf.TypeVerificationHelper.TypeInfo;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfLabel;
import com.android.tools.r8.cf.code.CfPosition;
import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.cf.code.frame.PreciseFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
@@ -622,16 +624,16 @@
instructions.add(frame);
}
- private FrameType getFrameType(BasicBlock liveBlock, TypeInfo typeInfo) {
+ private PreciseFrameType getFrameType(BasicBlock liveBlock, TypeInfo typeInfo) {
if (typeInfo instanceof InitializedTypeInfo) {
return FrameType.initialized(typeInfo.getDexType());
}
- FrameType type = findAllocator(liveBlock, typeInfo);
+ UninitializedFrameType type = findAllocator(liveBlock, typeInfo);
return type != null ? type : FrameType.initialized(typeInfo.getDexType());
}
- private FrameType findAllocator(BasicBlock liveBlock, TypeInfo typeInfo) {
- FrameType res;
+ private UninitializedFrameType findAllocator(BasicBlock liveBlock, TypeInfo typeInfo) {
+ UninitializedFrameType res;
Instruction definition;
if (typeInfo instanceof NewInstanceInfo) {
NewInstanceInfo newInstanceInfo = (NewInstanceInfo) typeInfo;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
index 4500da3..86fa768 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CfSourceCode.java
@@ -6,7 +6,6 @@
import static it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMaps.emptyMap;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfGoto;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfLabel;
@@ -15,6 +14,8 @@
import com.android.tools.r8.cf.code.CfSwitch;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.cf.code.frame.PreciseFrameType;
import com.android.tools.r8.errors.InvalidDebugInfoException;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
@@ -610,7 +611,7 @@
frame.forEachLocal(
(localIndex, frameType) -> locals[localIndex] = convertUninitialized(frameType));
int index = 0;
- for (FrameType frameType : frame.getStack()) {
+ for (PreciseFrameType frameType : frame.getStack()) {
stack[index++] = convertUninitialized(frameType);
}
// TODO(b/169135126) Assert that all values are precise.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ServiceLoaderSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/ServiceLoaderSourceCode.java
index 57de6e1..0aa439a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ServiceLoaderSourceCode.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ServiceLoaderSourceCode.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.cf.code.CfArrayStore;
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfLabel;
@@ -24,6 +23,7 @@
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexItemFactory;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
index 38682e7..324ecfa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/backports/BackportedMethods.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfConstString;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfGoto;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfIfCmp;
@@ -39,6 +38,7 @@
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
index 3378f64..00892fa 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/constantdynamic/ConstantDynamicClass.java
@@ -15,7 +15,6 @@
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfConstString;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfGoto;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfInstruction;
@@ -31,6 +30,7 @@
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.cf.code.CfTryCatch;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java
index 08b98e6..ba352b1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibrarySpecification.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.utils.Timing;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.Collection;
import java.util.List;
public interface DesugaredLibrarySpecification {
@@ -39,11 +40,14 @@
throws IOException;
MachineDesugaredLibrarySpecification toMachineSpecification(
- InternalOptions options, Path library, Timing timing, Path desugaredJDKLib)
+ InternalOptions options,
+ Collection<Path> library,
+ Timing timing,
+ Collection<Path> desugaredJDKLib)
throws IOException;
default MachineDesugaredLibrarySpecification toMachineSpecification(
- InternalOptions options, Path library, Timing timing) throws IOException {
+ InternalOptions options, Collection<Path> library, Timing timing) throws IOException {
assert !isLibraryCompilation();
return toMachineSpecification(options, library, timing, null);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryConversionCfProvider.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryConversionCfProvider.java
index ea0f8c0..29ecfd2 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryConversionCfProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryConversionCfProvider.java
@@ -41,6 +41,8 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryClasspathWrapperSynthesizeEventConsumer;
import com.android.tools.r8.ir.desugar.desugaredlibrary.apiconversion.DesugaredLibraryWrapperSynthesizerEventConsumer.DesugaredLibraryL8ProgramWrapperSynthesizerEventConsumer;
import com.android.tools.r8.ir.synthetic.apiconverter.APIConversionCfCodeProvider;
+import com.android.tools.r8.ir.synthetic.apiconverter.EqualsCfCodeProvider;
+import com.android.tools.r8.ir.synthetic.apiconverter.HashCodeCfCodeProvider;
import com.android.tools.r8.utils.OptionalBool;
import java.util.ArrayList;
import java.util.Collection;
@@ -97,6 +99,33 @@
return wrapperSynthesizer.newSynthesizedMethod(methodToInstall, cfCode);
}
+ public DexEncodedMethod generateWrapperHashCode(DexField wrapperField) {
+ return wrapperSynthesizer.newSynthesizedMethod(
+ appView
+ .dexItemFactory()
+ .createMethod(
+ wrapperField.getHolderType(),
+ appView.dexItemFactory().createProto(appView.dexItemFactory().intType),
+ appView.dexItemFactory().hashCodeMethodName),
+ new HashCodeCfCodeProvider(appView, wrapperField.getHolderType(), wrapperField)
+ .generateCfCode());
+ }
+
+ public DexEncodedMethod generateWrapperEquals(DexField wrapperField) {
+ return wrapperSynthesizer.newSynthesizedMethod(
+ appView
+ .dexItemFactory()
+ .createMethod(
+ wrapperField.getHolderType(),
+ appView
+ .dexItemFactory()
+ .createProto(
+ appView.dexItemFactory().booleanType, appView.dexItemFactory().objectType),
+ appView.dexItemFactory().equalsMethodName),
+ new EqualsCfCodeProvider(appView, wrapperField.getHolderType(), wrapperField)
+ .generateCfCode());
+ }
+
public DexEncodedMethod generateVivifiedWrapperConversionWithoutCode(
DexMethod method, DexField wrapperField) {
DexMethod methodToInstall =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
index 5a34df5..a930b12 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/apiconversion/DesugaredLibraryWrapperSynthesizer.java
@@ -42,6 +42,7 @@
import com.android.tools.r8.synthesis.SyntheticItems.SyntheticKindSelector;
import com.android.tools.r8.synthesis.SyntheticMethodBuilder;
import com.android.tools.r8.utils.StringDiagnostic;
+import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@@ -632,6 +633,13 @@
return generatedMethods;
}
+ private Collection<DexEncodedMethod> synthesizeHashCodeAndEquals(
+ DexProgramClass wrapper, DexEncodedField wrapperField) {
+ return ImmutableList.of(
+ conversionCfProvider.generateWrapperHashCode(wrapperField.getReference()),
+ conversionCfProvider.generateWrapperEquals(wrapperField.getReference()));
+ }
+
DexEncodedMethod newSynthesizedMethod(DexMethod methodToInstall, Code code) {
MethodAccessFlags newFlags =
MethodAccessFlags.fromSharedAccessFlags(
@@ -752,6 +760,7 @@
field,
eventConsumer,
() -> processingContext.createUniqueContext(wrapper))));
+ wrapper.addVirtualMethods(synthesizeHashCodeAndEquals(wrapper, wrapperField));
DexProgramClass vivifiedWrapper =
getExistingProgramWrapper(context, kinds -> kinds.VIVIFIED_WRAPPER);
DexEncodedField vivifiedWrapperField = getWrapperUniqueEncodedField(vivifiedWrapper);
@@ -765,5 +774,7 @@
field,
eventConsumer,
() -> processingContext.createUniqueContext(wrapper))));
+ vivifiedWrapper.addVirtualMethods(
+ synthesizeHashCodeAndEquals(vivifiedWrapper, vivifiedWrapperField));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
index 2a5f49f..e3696af 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecification.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.utils.Timing;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.Collection;
import java.util.List;
public class HumanDesugaredLibrarySpecification implements DesugaredLibrarySpecification {
@@ -97,7 +98,10 @@
@Override
public MachineDesugaredLibrarySpecification toMachineSpecification(
- InternalOptions options, Path library, Timing timing, Path desugaredJDKLib)
+ InternalOptions options,
+ Collection<Path> library,
+ Timing timing,
+ Collection<Path> desugaredJDKLib)
throws IOException {
return new HumanToMachineSpecificationConverter(timing)
.convertForTesting(this, desugaredJDKLib, library, options);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
index 01fda4a..e669bfb 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/legacyspecification/LegacyDesugaredLibrarySpecification.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.utils.Timing;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -127,7 +128,10 @@
@Override
public MachineDesugaredLibrarySpecification toMachineSpecification(
- InternalOptions options, Path library, Timing timing, Path desugaredJDKLib)
+ InternalOptions options,
+ Collection<Path> library,
+ Timing timing,
+ Collection<Path> desugaredJDKLib)
throws IOException {
return new LegacyToHumanSpecificationConverter(timing)
.convertForTesting(this, desugaredJDKLib, library, options)
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/AppForSpecConversion.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/AppForSpecConversion.java
index 0df69b0..74c31b4 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/AppForSpecConversion.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/AppForSpecConversion.java
@@ -12,13 +12,14 @@
import com.android.tools.r8.utils.Timing;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.Collection;
import java.util.concurrent.ExecutorService;
public class AppForSpecConversion {
public static DexApplication readAppForTesting(
- Path desugaredJDKLib,
- Path androidLib,
+ Collection<Path> desugaredJDKLib,
+ Collection<Path> androidLib,
InternalOptions options,
boolean libraryCompilation,
Timing timing)
@@ -27,9 +28,9 @@
assert !libraryCompilation || desugaredJDKLib != null;
AndroidApp.Builder builder = AndroidApp.builder();
if (libraryCompilation) {
- builder.addProgramFile(desugaredJDKLib);
+ builder.addProgramFiles(desugaredJDKLib);
}
- AndroidApp inputApp = builder.addLibraryFile(androidLib).build();
+ AndroidApp inputApp = builder.addLibraryFiles(androidLib).build();
DexApplication app = internalReadApp(inputApp, options, timing);
timing.end();
return app;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
index 99d816e..dea440e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineSpecificationConverter.java
@@ -29,6 +29,7 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.List;
import java.util.Set;
@@ -45,8 +46,8 @@
public MachineDesugaredLibrarySpecification convertForTesting(
HumanDesugaredLibrarySpecification humanSpec,
- Path desugaredJDKLib,
- Path androidLib,
+ Collection<Path> desugaredJDKLib,
+ Collection<Path> androidLib,
InternalOptions options)
throws IOException {
DexApplication app =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java
index 18147b5..c0d9157 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineWrapperConverter.java
@@ -70,7 +70,11 @@
while (!workList.isEmpty()) {
DexClass dexClass = workList.removeFirst();
for (DexEncodedMethod virtualMethod : dexClass.virtualMethods()) {
- if (!virtualMethod.isPrivateMethod()) {
+ if (!virtualMethod.isPrivateMethod()
+ // Don't include hashCode and equals overrides, as hashCode and equals are added to
+ // all wrappers regardless.
+ && (!appInfo.dexItemFactory().objectMembers.hashCode.match(virtualMethod))
+ && (!appInfo.dexItemFactory().objectMembers.equals.match(virtualMethod))) {
assert virtualMethod.isProtectedMethod() || virtualMethod.isPublicMethod();
boolean alreadyAdded = wrappers.contains(equivalence.wrap(virtualMethod.getReference()));
// This looks quadratic but given the size of the collections met in practice for
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
index baa4178..9ac3369 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/LegacyToHumanSpecificationConverter.java
@@ -41,6 +41,7 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@@ -61,8 +62,8 @@
public void convertAllAPILevels(
StringResource inputSpecification,
- Path desugaredJDKLib,
- Path androidLib,
+ Collection<Path> desugaredJDKLib,
+ Collection<Path> androidLib,
StringConsumer output)
throws IOException {
InternalOptions options = new InternalOptions();
@@ -77,8 +78,8 @@
public MultiAPILevelHumanDesugaredLibrarySpecification convertAllAPILevels(
MultiAPILevelLegacyDesugaredLibrarySpecification legacySpec,
- Path desugaredJDKLib,
- Path androidLib,
+ Collection<Path> desugaredJDKLib,
+ Collection<Path> androidLib,
InternalOptions options)
throws IOException {
timing.begin("Legacy to human all API convert");
@@ -108,8 +109,8 @@
public HumanDesugaredLibrarySpecification convertForTesting(
LegacyDesugaredLibrarySpecification legacySpec,
- Path desugaredJDKLib,
- Path androidLib,
+ Collection<Path> desugaredJDKLib,
+ Collection<Path> androidLib,
InternalOptions options)
throws IOException {
DexApplication app =
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
index a6384e1..b288d9a 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/icce/AlwaysThrowingInstructionDesugaring.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringCollection;
import com.android.tools.r8.ir.desugar.CfInstructionDesugaringEventConsumer;
import com.android.tools.r8.ir.desugar.DesugarDescription;
+import com.android.tools.r8.ir.desugar.DesugarDescription.ScanCallback;
import com.android.tools.r8.ir.desugar.FreshLocalProvider;
import com.android.tools.r8.ir.desugar.LocalStackAllocator;
import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations;
@@ -105,46 +106,46 @@
getThrowInstructions(
appView,
invoke,
- resolutionResult,
localStackAllocator,
eventConsumer,
context,
- methodProcessingContext))
+ methodProcessingContext,
+ getMethodSynthesizerForThrowing(appView, invoke, resolutionResult, context)))
.build();
}
+ public static DesugarDescription computeInvokeAsThrowNSMERewrite(
+ AppView<?> appView, CfInvoke invoke, ScanCallback scanCallback) {
+ DesugarDescription.Builder builder =
+ DesugarDescription.builder()
+ .setDesugarRewrite(
+ (freshLocalProvider,
+ localStackAllocator,
+ eventConsumer,
+ context,
+ methodProcessingContext,
+ dexItemFactory) ->
+ getThrowInstructions(
+ appView,
+ invoke,
+ localStackAllocator,
+ eventConsumer,
+ context,
+ methodProcessingContext,
+ UtilityMethodsForCodeOptimizations
+ ::synthesizeThrowNoSuchMethodErrorMethod));
+ builder.addScanEffect(scanCallback);
+ return builder.build();
+ }
+
private static Collection<CfInstruction> getThrowInstructions(
AppView<?> appView,
CfInvoke invoke,
- MethodResolutionResult resolutionResult,
LocalStackAllocator localStackAllocator,
CfInstructionDesugaringEventConsumer eventConsumer,
ProgramMethod context,
- MethodProcessingContext methodProcessingContext) {
- MethodSynthesizerConsumer methodSynthesizerConsumer = null;
- if (resolutionResult == null) {
- methodSynthesizerConsumer =
- UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
- } else if (resolutionResult.isSingleResolution()) {
- if (resolutionResult.getResolvedMethod().isStatic() != invoke.isInvokeStatic()) {
- methodSynthesizerConsumer =
- UtilityMethodsForCodeOptimizations::synthesizeThrowIncompatibleClassChangeErrorMethod;
- }
- } else if (resolutionResult.isFailedResolution()) {
- FailedResolutionResult failedResolutionResult = resolutionResult.asFailedResolution();
- AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
- if (failedResolutionResult.isIllegalAccessErrorResult(context.getHolder(), appInfo)) {
- methodSynthesizerConsumer =
- UtilityMethodsForCodeOptimizations::synthesizeThrowIllegalAccessErrorMethod;
- } else if (failedResolutionResult.isNoSuchMethodErrorResult(context.getHolder(), appInfo)) {
- methodSynthesizerConsumer =
- UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
- } else if (failedResolutionResult.isIncompatibleClassChangeErrorResult()) {
- methodSynthesizerConsumer =
- UtilityMethodsForCodeOptimizations::synthesizeThrowIncompatibleClassChangeErrorMethod;
- }
- }
-
+ MethodProcessingContext methodProcessingContext,
+ MethodSynthesizerConsumer methodSynthesizerConsumer) {
if (methodSynthesizerConsumer == null) {
assert false;
return null;
@@ -198,4 +199,32 @@
}
return replacement;
}
+
+ private static MethodSynthesizerConsumer getMethodSynthesizerForThrowing(
+ AppView<?> appView,
+ CfInvoke invoke,
+ MethodResolutionResult resolutionResult,
+ ProgramMethod context) {
+ if (resolutionResult == null) {
+ return UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
+ } else if (resolutionResult.isSingleResolution()) {
+ if (resolutionResult.getResolvedMethod().isStatic() != invoke.isInvokeStatic()) {
+ return UtilityMethodsForCodeOptimizations
+ ::synthesizeThrowIncompatibleClassChangeErrorMethod;
+ }
+ } else if (resolutionResult.isFailedResolution()) {
+ FailedResolutionResult failedResolutionResult = resolutionResult.asFailedResolution();
+ AppInfoWithClassHierarchy appInfo = appView.appInfoForDesugaring();
+ if (failedResolutionResult.isIllegalAccessErrorResult(context.getHolder(), appInfo)) {
+ return UtilityMethodsForCodeOptimizations::synthesizeThrowIllegalAccessErrorMethod;
+ } else if (failedResolutionResult.isNoSuchMethodErrorResult(context.getHolder(), appInfo)) {
+ return UtilityMethodsForCodeOptimizations::synthesizeThrowNoSuchMethodErrorMethod;
+ } else if (failedResolutionResult.isIncompatibleClassChangeErrorResult()) {
+ return UtilityMethodsForCodeOptimizations
+ ::synthesizeThrowIncompatibleClassChangeErrorMethod;
+ }
+ }
+
+ return null;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
index bc8ebd0..8e8541b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceMethodRewriter.java
@@ -44,6 +44,7 @@
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.android.tools.r8.utils.structural.Ordered;
import com.google.common.collect.Iterables;
@@ -711,7 +712,23 @@
}
}
- return computeEmulatedInterfaceInvokeSpecial(clazz, invokedMethod, context);
+ DesugarDescription emulatedInterfaceDesugaring =
+ computeEmulatedInterfaceInvokeSpecial(clazz, invokedMethod, context);
+ if (!emulatedInterfaceDesugaring.needsDesugaring() && context.isDefaultMethod()) {
+ return AlwaysThrowingInstructionDesugaring.computeInvokeAsThrowNSMERewrite(
+ appView,
+ invoke,
+ () ->
+ appView
+ .reporter()
+ .warning(
+ new StringDiagnostic(
+ "Interface method desugaring has inserted NoSuchMethodError replacing a"
+ + " super call in "
+ + context.toSourceString(),
+ context.getOrigin())));
+ }
+ return emulatedInterfaceDesugaring;
}
private DesugarDescription computeEmulatedInterfaceInvokeSpecial(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordCfMethods.java b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordCfMethods.java
index 8e854ac..e46b8d6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/records/RecordCfMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/records/RecordCfMethods.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfConstString;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfGoto;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfIfCmp;
@@ -27,6 +26,7 @@
import com.android.tools.r8.cf.code.CfReturn;
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfStore;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCfMethods.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCfMethods.java
index 127b47b..527fb13 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCfMethods.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCfMethods.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.cf.code.CfArrayStore;
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfGoto;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfIfCmp;
@@ -28,6 +27,7 @@
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.cf.code.CfThrow;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizations.java b/src/main/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizations.java
index 2cdaa8e..162a1cc 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizations.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizations.java
@@ -9,7 +9,6 @@
package com.android.tools.r8.ir.optimize.templates;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfLabel;
@@ -18,6 +17,7 @@
import com.android.tools.r8.cf.code.CfReturnVoid;
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfThrow;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EmulateDispatchSyntheticCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EmulateDispatchSyntheticCfCodeProvider.java
index 480490c..2852ce9 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EmulateDispatchSyntheticCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EmulateDispatchSyntheticCfCodeProvider.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.cf.code.CfCheckCast;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfInstanceOf;
import com.android.tools.r8.cf.code.CfInstruction;
@@ -15,6 +14,7 @@
import com.android.tools.r8.cf.code.CfLoad;
import com.android.tools.r8.cf.code.CfReturn;
import com.android.tools.r8.cf.code.CfReturnVoid;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexMethod;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
index 7de8d21..34e3f71 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfConstString;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfIfCmp;
import com.android.tools.r8.cf.code.CfInstruction;
@@ -22,6 +21,7 @@
import com.android.tools.r8.cf.code.CfStaticFieldRead;
import com.android.tools.r8.cf.code.CfStaticFieldWrite;
import com.android.tools.r8.cf.code.CfThrow;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/RecordCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/RecordCfCodeProvider.java
index a6da57c..f328c2c 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/RecordCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/RecordCfCodeProvider.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.cf.code.CfCheckCast;
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfIfCmp;
import com.android.tools.r8.cf.code.CfInstanceFieldRead;
import com.android.tools.r8.cf.code.CfInstruction;
@@ -19,6 +18,7 @@
import com.android.tools.r8.cf.code.CfRecordFieldValues;
import com.android.tools.r8.cf.code.CfReturn;
import com.android.tools.r8.cf.code.CfStore;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexField;
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/EqualsCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/EqualsCfCodeProvider.java
new file mode 100644
index 0000000..d1a4bf3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/EqualsCfCodeProvider.java
@@ -0,0 +1,88 @@
+// 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.ir.synthetic.apiconverter;
+
+import com.android.tools.r8.cf.code.CfCheckCast;
+import com.android.tools.r8.cf.code.CfFrame;
+import com.android.tools.r8.cf.code.CfGoto;
+import com.android.tools.r8.cf.code.CfIf;
+import com.android.tools.r8.cf.code.CfInstanceFieldRead;
+import com.android.tools.r8.cf.code.CfInstanceOf;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.cf.code.CfLoad;
+import com.android.tools.r8.cf.code.CfReturn;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.If;
+import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.synthetic.SyntheticCfCodeProvider;
+import it.unimi.dsi.fastutil.ints.Int2ObjectAVLTreeMap;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import org.objectweb.asm.Opcodes;
+
+public class EqualsCfCodeProvider extends SyntheticCfCodeProvider {
+
+ private final DexField wrapperField;
+
+ public EqualsCfCodeProvider(AppView<?> appView, DexType holder, DexField wrapperField) {
+ super(appView, holder);
+ this.wrapperField = wrapperField;
+ }
+
+ @Override
+ public CfCode generateCfCode() {
+ // return wrapperField.equals(
+ // other instanceof WrapperType ? ((WrapperType) other).wrapperField : other);
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ List<CfInstruction> instructions = new ArrayList<>();
+ instructions.add(new CfLoad(ValueType.OBJECT, 0));
+ instructions.add(new CfInstanceFieldRead(wrapperField));
+ instructions.add(new CfLoad(ValueType.OBJECT, 1));
+ DexType wrapperType = wrapperField.getHolderType();
+ instructions.add(new CfInstanceOf(wrapperType));
+ instructions.add(new CfIf(If.Type.EQ, ValueType.INT, label1));
+ instructions.add(new CfLoad(ValueType.OBJECT, 1));
+ instructions.add(new CfCheckCast(wrapperType));
+ instructions.add(new CfInstanceFieldRead(wrapperField));
+ instructions.add(new CfGoto(label2));
+ instructions.add(label1);
+ instructions.add(
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1},
+ new FrameType[] {
+ FrameType.initialized(wrapperType),
+ FrameType.initialized(appView.dexItemFactory().objectType)
+ }),
+ new ArrayDeque<>(Arrays.asList(FrameType.initialized(wrapperType)))));
+ instructions.add(new CfLoad(ValueType.OBJECT, 1));
+ instructions.add(label2);
+ instructions.add(
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1},
+ new FrameType[] {
+ FrameType.initialized(wrapperType),
+ FrameType.initialized(appView.dexItemFactory().objectType)
+ }),
+ new ArrayDeque<>(
+ Arrays.asList(
+ FrameType.initialized(wrapperType),
+ FrameType.initialized(appView.dexItemFactory().objectType)))));
+ instructions.add(
+ new CfInvoke(Opcodes.INVOKEVIRTUAL, appView.dexItemFactory().objectMembers.equals, false));
+ instructions.add(new CfReturn(ValueType.INT));
+ return standardCfCodeFromInstructions(instructions);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/HashCodeCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/HashCodeCfCodeProvider.java
new file mode 100644
index 0000000..3c5f717
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/HashCodeCfCodeProvider.java
@@ -0,0 +1,42 @@
+// 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.ir.synthetic.apiconverter;
+
+import com.android.tools.r8.cf.code.CfInstanceFieldRead;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfInvoke;
+import com.android.tools.r8.cf.code.CfLoad;
+import com.android.tools.r8.cf.code.CfReturn;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.synthetic.SyntheticCfCodeProvider;
+import java.util.ArrayList;
+import java.util.List;
+import org.objectweb.asm.Opcodes;
+
+public class HashCodeCfCodeProvider extends SyntheticCfCodeProvider {
+
+ private final DexField wrapperField;
+
+ public HashCodeCfCodeProvider(AppView<?> appView, DexType holder, DexField wrapperField) {
+ super(appView, holder);
+ this.wrapperField = wrapperField;
+ }
+
+ @Override
+ public CfCode generateCfCode() {
+ List<CfInstruction> instructions = new ArrayList<>();
+ instructions.add(new CfLoad(ValueType.OBJECT, 0));
+ instructions.add(new CfInstanceFieldRead(wrapperField));
+ instructions.add(
+ new CfInvoke(
+ Opcodes.INVOKEVIRTUAL, appView.dexItemFactory().objectMembers.hashCode, false));
+ instructions.add(new CfReturn(ValueType.INT));
+ return standardCfCodeFromInstructions(instructions);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/NullableConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/NullableConversionCfCodeProvider.java
index a4f9714..10e267b 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/NullableConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/apiconverter/NullableConversionCfCodeProvider.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.cf.code.CfConstNull;
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfGoto;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfIfCmp;
@@ -29,6 +28,7 @@
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfStaticFieldRead;
import com.android.tools.r8.cf.code.CfStore;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexEncodedField;
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
index fc3c106..5c9e671 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/BottomCfFrameState.java
@@ -5,7 +5,9 @@
package com.android.tools.r8.optimize.interfaces.analysis;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.cf.code.frame.PreciseFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
@@ -33,12 +35,23 @@
}
@Override
+ public CfFrameState checkLocals(AppView<?> appView, CfFrame frame) {
+ return new ConcreteCfFrameState().checkLocals(appView, frame);
+ }
+
+ @Override
+ public CfFrameState checkStack(AppView<?> appView, CfFrame frame) {
+ return new ConcreteCfFrameState().checkStack(appView, frame);
+ }
+
+ @Override
public CfFrameState clear() {
return this;
}
@Override
- public CfFrameState markInitialized(FrameType uninitializedType, DexType initializedType) {
+ public CfFrameState markInitialized(
+ UninitializedFrameType uninitializedType, DexType initializedType) {
// Initializing an uninitialized type is a no-op when the frame is empty.
return this;
}
@@ -49,7 +62,7 @@
}
@Override
- public ErroneousCfFrameState pop(BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
+ public ErroneousCfFrameState pop(BiFunction<CfFrameState, PreciseFrameType, CfFrameState> fn) {
return pop();
}
@@ -63,7 +76,7 @@
public ErroneousCfFrameState popInitialized(
AppView<?> appView,
DexType expectedType,
- BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
+ BiFunction<CfFrameState, PreciseFrameType, CfFrameState> fn) {
return pop();
}
@@ -78,7 +91,7 @@
}
@Override
- public CfFrameState push(CfAnalysisConfig config, FrameType frameType) {
+ public CfFrameState push(CfAnalysisConfig config, PreciseFrameType frameType) {
return new ConcreteCfFrameState().push(config, frameType);
}
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
index b12cc01..2131f02 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/CfFrameState.java
@@ -9,7 +9,9 @@
import com.android.tools.r8.cf.code.CfAssignability;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.cf.code.frame.PreciseFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -101,14 +103,18 @@
public abstract CfFrameState check(AppView<?> appView, CfFrame frame);
+ public abstract CfFrameState checkLocals(AppView<?> appView, CfFrame frame);
+
+ public abstract CfFrameState checkStack(AppView<?> appView, CfFrame frame);
+
public abstract CfFrameState clear();
public abstract CfFrameState markInitialized(
- FrameType uninitializedType, DexType initializedType);
+ UninitializedFrameType uninitializedType, DexType initializedType);
public abstract CfFrameState pop();
- public abstract CfFrameState pop(BiFunction<CfFrameState, FrameType, CfFrameState> fn);
+ public abstract CfFrameState pop(BiFunction<CfFrameState, PreciseFrameType, CfFrameState> fn);
public abstract CfFrameState popAndInitialize(
AppView<?> appView, DexMethod constructor, CfAnalysisConfig config);
@@ -120,7 +126,7 @@
public abstract CfFrameState popInitialized(
AppView<?> appView,
DexType expectedType,
- BiFunction<CfFrameState, FrameType, CfFrameState> fn);
+ BiFunction<CfFrameState, PreciseFrameType, CfFrameState> fn);
public abstract CfFrameState popInitialized(AppView<?> appView, DexType... expectedTypes);
@@ -143,11 +149,11 @@
public final CfFrameState popInitialized(
AppView<?> appView,
ValueType valueType,
- BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
+ BiFunction<CfFrameState, PreciseFrameType, CfFrameState> fn) {
return popInitialized(appView, valueType.toDexType(appView.dexItemFactory()), fn);
}
- public final CfFrameState popObject(BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
+ public final CfFrameState popObject(BiFunction<CfFrameState, PreciseFrameType, CfFrameState> fn) {
return pop(
(state, head) ->
head.isObject() ? fn.apply(state, head) : errorUnexpectedStack(head, ValueType.OBJECT));
@@ -158,7 +164,7 @@
AppView<?> appView,
DexType expectedType,
CfAnalysisConfig config,
- BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
+ BiFunction<CfFrameState, PreciseFrameType, CfFrameState> fn) {
return pop(
(state, head) ->
head.isObject()
@@ -174,7 +180,7 @@
return popSingle((state, single) -> state);
}
- public final CfFrameState popSingle(BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
+ public final CfFrameState popSingle(BiFunction<CfFrameState, PreciseFrameType, CfFrameState> fn) {
return pop(
(state, single) ->
single.isSingle()
@@ -183,22 +189,22 @@
}
public final CfFrameState popSingles(
- TriFunction<CfFrameState, FrameType, FrameType, CfFrameState> fn) {
+ TriFunction<CfFrameState, PreciseFrameType, PreciseFrameType, CfFrameState> fn) {
return popSingle(
(state1, single1) ->
state1.popSingle((state2, single2) -> fn.apply(state2, single2, single1)));
}
public final CfFrameState popSingleOrWide(
- BiFunction<CfFrameState, FrameType, CfFrameState> singleFn,
- BiFunction<CfFrameState, FrameType, CfFrameState> wideFn) {
+ BiFunction<CfFrameState, PreciseFrameType, CfFrameState> singleFn,
+ BiFunction<CfFrameState, PreciseFrameType, CfFrameState> wideFn) {
return pop(
(state, head) -> head.isSingle() ? singleFn.apply(state, head) : wideFn.apply(state, head));
}
public final CfFrameState popSingleSingleOrWide(
- TriFunction<CfFrameState, FrameType, FrameType, CfFrameState> singleSingleFn,
- BiFunction<CfFrameState, FrameType, CfFrameState> wideFn) {
+ TriFunction<CfFrameState, PreciseFrameType, PreciseFrameType, CfFrameState> singleSingleFn,
+ BiFunction<CfFrameState, PreciseFrameType, CfFrameState> wideFn) {
return popSingleOrWide(
(state1, single1) ->
state1.popSingle((state2, single2) -> singleSingleFn.apply(state2, single2, single1)),
@@ -207,24 +213,27 @@
public abstract CfFrameState push(CfAnalysisConfig config, DexType type);
- public abstract CfFrameState push(CfAnalysisConfig config, FrameType frameType);
+ public abstract CfFrameState push(CfAnalysisConfig config, PreciseFrameType frameType);
public final CfFrameState push(
- CfAnalysisConfig config, FrameType frameType, FrameType frameType2) {
+ CfAnalysisConfig config, PreciseFrameType frameType, PreciseFrameType frameType2) {
return push(config, frameType).push(config, frameType2);
}
public final CfFrameState push(
- CfAnalysisConfig config, FrameType frameType, FrameType frameType2, FrameType frameType3) {
+ CfAnalysisConfig config,
+ PreciseFrameType frameType,
+ PreciseFrameType frameType2,
+ PreciseFrameType frameType3) {
return push(config, frameType).push(config, frameType2).push(config, frameType3);
}
public final CfFrameState push(
CfAnalysisConfig config,
- FrameType frameType,
- FrameType frameType2,
- FrameType frameType3,
- FrameType frameType4) {
+ PreciseFrameType frameType,
+ PreciseFrameType frameType2,
+ PreciseFrameType frameType3,
+ PreciseFrameType frameType4) {
return push(config, frameType)
.push(config, frameType2)
.push(config, frameType3)
@@ -233,11 +242,11 @@
public final CfFrameState push(
CfAnalysisConfig config,
- FrameType frameType,
- FrameType frameType2,
- FrameType frameType3,
- FrameType frameType4,
- FrameType frameType5) {
+ PreciseFrameType frameType,
+ PreciseFrameType frameType2,
+ PreciseFrameType frameType3,
+ PreciseFrameType frameType4,
+ PreciseFrameType frameType5) {
return push(config, frameType)
.push(config, frameType2)
.push(config, frameType3)
@@ -247,12 +256,12 @@
public final CfFrameState push(
CfAnalysisConfig config,
- FrameType frameType,
- FrameType frameType2,
- FrameType frameType3,
- FrameType frameType4,
- FrameType frameType5,
- FrameType frameType6) {
+ PreciseFrameType frameType,
+ PreciseFrameType frameType2,
+ PreciseFrameType frameType3,
+ PreciseFrameType frameType4,
+ PreciseFrameType frameType5,
+ PreciseFrameType frameType6) {
return push(config, frameType)
.push(config, frameType2)
.push(config, frameType3)
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
index a76a6d3..e920d8e 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ConcreteCfFrameState.java
@@ -10,8 +10,10 @@
import com.android.tools.r8.cf.code.CfAssignability;
import com.android.tools.r8.cf.code.CfAssignability.AssignabilityResult;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.cf.code.frame.PreciseFrameType;
import com.android.tools.r8.cf.code.frame.SingleFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
import com.android.tools.r8.cf.code.frame.WideFrameType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexMethod;
@@ -35,15 +37,15 @@
public class ConcreteCfFrameState extends CfFrameState {
private final Int2ObjectAVLTreeMap<FrameType> locals;
- private final ArrayDeque<FrameType> stack;
+ private final ArrayDeque<PreciseFrameType> stack;
private int stackHeight;
ConcreteCfFrameState() {
this(new Int2ObjectAVLTreeMap<>(), new ArrayDeque<>(), 0);
}
- ConcreteCfFrameState(
- Int2ObjectAVLTreeMap<FrameType> locals, ArrayDeque<FrameType> stack, int stackHeight) {
+ public ConcreteCfFrameState(
+ Int2ObjectAVLTreeMap<FrameType> locals, ArrayDeque<PreciseFrameType> stack, int stackHeight) {
this.locals = locals;
this.stack = stack;
this.stackHeight = stackHeight;
@@ -78,28 +80,53 @@
}
@Override
+ public CfFrameState checkLocals(AppView<?> appView, CfFrame frame) {
+ AssignabilityResult assignabilityResult =
+ CfAssignability.isLocalsAssignable(locals, frame.getLocals(), appView);
+ if (assignabilityResult.isFailed()) {
+ return error(assignabilityResult.asFailed().getMessage());
+ }
+ return this;
+ }
+
+ @Override
+ public CfFrameState checkStack(AppView<?> appView, CfFrame frame) {
+ AssignabilityResult assignabilityResult =
+ CfAssignability.isStackAssignable(stack, frame.getStack(), appView);
+ if (assignabilityResult.isFailed()) {
+ return error(assignabilityResult.asFailed().getMessage());
+ }
+ return this;
+ }
+
+ @Override
public CfFrameState clear() {
return bottom();
}
@Override
- public CfFrameState markInitialized(FrameType uninitializedType, DexType initializedType) {
+ public CfFrameState markInitialized(
+ UninitializedFrameType uninitializedType, DexType initializedType) {
if (uninitializedType.isInitialized()) {
return error("Unexpected attempt to initialize already initialized type");
}
for (Int2ObjectMap.Entry<FrameType> entry : locals.int2ObjectEntrySet()) {
FrameType frameType = entry.getValue();
- FrameType initializedFrameType =
- getInitializedFrameType(uninitializedType, frameType, initializedType);
- entry.setValue(initializedFrameType);
+ if (frameType.isUninitialized()) {
+ entry.setValue(
+ getInitializedFrameType(
+ uninitializedType, frameType.asUninitialized(), initializedType));
+ }
}
// TODO(b/214496607): By using a collection that supports element replacement this could mutate
// the existing stack instead of building a new one.
- ArrayDeque<FrameType> newStack = new ArrayDeque<>();
- for (FrameType frameType : stack) {
- FrameType initializedFrameType =
- getInitializedFrameType(uninitializedType, frameType, initializedType);
- newStack.addLast(initializedFrameType);
+ ArrayDeque<PreciseFrameType> newStack = new ArrayDeque<>();
+ for (PreciseFrameType frameType : stack) {
+ newStack.addLast(
+ frameType.isUninitialized()
+ ? getInitializedFrameType(
+ uninitializedType, frameType.asUninitialized(), initializedType)
+ : frameType);
}
return new ConcreteCfFrameState(locals, newStack, stackHeight);
}
@@ -110,12 +137,12 @@
}
@Override
- public CfFrameState pop(BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
+ public CfFrameState pop(BiFunction<CfFrameState, PreciseFrameType, CfFrameState> fn) {
if (stack.isEmpty()) {
// Return the same error as when popping from the bottom state.
return bottom().pop();
}
- FrameType frameType = stack.removeLast();
+ PreciseFrameType frameType = stack.removeLast();
stackHeight -= frameType.getWidth();
return fn.apply(this, frameType);
}
@@ -125,16 +152,17 @@
AppView<?> appView, DexMethod constructor, CfAnalysisConfig config) {
return pop(
(state, frameType) -> {
- if (frameType.isUninitializedObject()) {
+ if (frameType.isUninitialized()) {
if (frameType.isUninitializedThis()) {
if (constructor.getHolderType() == config.getCurrentContext().getHolderType()
|| config.isImmediateSuperClassOfCurrentContext(constructor.getHolderType())) {
- return state.markInitialized(frameType, config.getCurrentContext().getHolderType());
+ return state.markInitialized(
+ frameType.asUninitializedThis(), config.getCurrentContext().getHolderType());
}
} else if (frameType.isUninitializedNew()) {
DexType uninitializedNewType = frameType.getUninitializedNewType();
if (constructor.getHolderType() == uninitializedNewType) {
- return state.markInitialized(frameType, uninitializedNewType);
+ return state.markInitialized(frameType.asUninitializedNew(), uninitializedNewType);
}
}
return popAndInitializeConstructorMismatchError(frameType, constructor, config);
@@ -144,8 +172,8 @@
}
private ErroneousCfFrameState popAndInitializeConstructorMismatchError(
- FrameType frameType, DexMethod constructor, CfAnalysisConfig config) {
- assert frameType.isUninitializedObject();
+ PreciseFrameType frameType, DexMethod constructor, CfAnalysisConfig config) {
+ assert frameType.isUninitialized();
StringBuilder message = new StringBuilder("Constructor mismatch, expected constructor from ");
if (frameType.isUninitializedNew()) {
message.append(frameType.getUninitializedNewType().getTypeName());
@@ -159,7 +187,7 @@
return error(message.toString());
}
- private ErroneousCfFrameState popAndInitializeInitializedObjectError(FrameType frameType) {
+ private ErroneousCfFrameState popAndInitializeInitializedObjectError(PreciseFrameType frameType) {
return error("Unexpected attempt to initialize " + formatActual(frameType));
}
@@ -167,7 +195,7 @@
public CfFrameState popInitialized(
AppView<?> appView,
DexType expectedType,
- BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
+ BiFunction<CfFrameState, PreciseFrameType, CfFrameState> fn) {
return pop(
(state, frameType) -> {
if (frameType.isInitialized()) {
@@ -195,7 +223,7 @@
}
@Override
- public CfFrameState push(CfAnalysisConfig config, FrameType frameType) {
+ public CfFrameState push(CfAnalysisConfig config, PreciseFrameType frameType) {
int newStackHeight = stackHeight + frameType.getWidth();
if (newStackHeight > config.getMaxStack()) {
return pushError(config, frameType);
@@ -205,7 +233,7 @@
return this;
}
- private ErroneousCfFrameState pushError(CfAnalysisConfig config, FrameType frameType) {
+ private ErroneousCfFrameState pushError(CfAnalysisConfig config, PreciseFrameType frameType) {
return error(
"The max stack height of "
+ config.getMaxStack()
@@ -230,7 +258,7 @@
frameType.getInitializedType(appView.dexItemFactory()), expectedType, appView)) {
return fn.apply(this, frameType);
}
- } else if (frameType.isUninitializedObject() && expectedType.isObject()) {
+ } else if (frameType.isUninitialized() && expectedType.isObject()) {
return fn.apply(this, frameType);
}
return errorUnexpectedLocal(frameType, expectedType, localIndex);
@@ -380,7 +408,7 @@
SingleFrameType frameType,
SingleFrameType otherFrameType,
CfFrame.Builder builder) {
- builder.store(localIndex, frameType.join(otherFrameType).asFrameType());
+ builder.store(localIndex, frameType.join(otherFrameType));
}
private void joinWideLocalsWithSameIndex(
@@ -388,7 +416,7 @@
WideFrameType frameType,
WideFrameType otherFrameType,
CfFrame.Builder builder) {
- builder.store(localIndex, frameType.join(otherFrameType).asFrameType());
+ builder.store(localIndex, frameType.join(otherFrameType));
}
// TODO(b/231521474): By splitting each wide type into single left/right types, the join of each
@@ -493,13 +521,13 @@
setSingleLocalToTop(localIndex + 1, builder);
}
- private ErroneousCfFrameState joinStack(Deque<FrameType> stack, CfFrame.Builder builder) {
- Iterator<FrameType> iterator = this.stack.iterator();
- Iterator<FrameType> otherIterator = stack.iterator();
+ private ErroneousCfFrameState joinStack(Deque<PreciseFrameType> stack, CfFrame.Builder builder) {
+ Iterator<PreciseFrameType> iterator = this.stack.iterator();
+ Iterator<PreciseFrameType> otherIterator = stack.iterator();
int stackIndex = 0;
while (iterator.hasNext() && otherIterator.hasNext()) {
- FrameType frameType = iterator.next();
- FrameType otherFrameType = otherIterator.next();
+ PreciseFrameType frameType = iterator.next();
+ PreciseFrameType otherFrameType = otherIterator.next();
if (frameType.isSingle() != otherFrameType.isSingle()) {
return error(
"Cannot join stacks, expected frame types at stack index "
@@ -509,19 +537,23 @@
+ " and "
+ formatActual(otherFrameType));
}
+ PreciseFrameType preciseJoin;
if (frameType.isSingle()) {
SingleFrameType join = frameType.asSingle().join(otherFrameType.asSingle());
if (join.isOneWord()) {
return joinStackImpreciseJoinError(stackIndex, frameType, otherFrameType);
}
- builder.push(join.asFrameType());
+ assert join.isPrecise();
+ preciseJoin = join.asPrecise();
} else {
WideFrameType join = frameType.asWide().join(otherFrameType.asWide());
if (join.isTwoWord()) {
return joinStackImpreciseJoinError(stackIndex, frameType, otherFrameType);
}
- builder.push(join.asFrameType());
+ assert join.isPrecise();
+ preciseJoin = join.asPrecise();
}
+ builder.push(preciseJoin);
stackIndex++;
}
if (iterator.hasNext() || otherIterator.hasNext()) {
@@ -531,7 +563,7 @@
}
private ErroneousCfFrameState joinStackImpreciseJoinError(
- int stackIndex, FrameType first, FrameType second) {
+ int stackIndex, PreciseFrameType first, PreciseFrameType second) {
return error(
"Cannot join stacks, expected frame types at stack index "
+ stackIndex
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
index 47e2d24..5f8569b 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/analysis/ErroneousCfFrameState.java
@@ -5,7 +5,9 @@
package com.android.tools.r8.optimize.interfaces.analysis;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
+import com.android.tools.r8.cf.code.frame.PreciseFrameType;
+import com.android.tools.r8.cf.code.frame.UninitializedFrameType;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
@@ -52,7 +54,7 @@
private static String format(FrameType frameType, FormatKind formatKind) {
if (frameType.isInitialized()) {
if (frameType.isObject()) {
- DexType initializedType = frameType.asSingleInitializedType().getInitializedType();
+ DexType initializedType = frameType.asInitializedReferenceType().getInitializedType();
if (initializedType.isArrayType()) {
return initializedType.getTypeName();
} else if (initializedType.isClassType()) {
@@ -65,7 +67,7 @@
assert frameType.isPrimitive();
return "primitive " + frameType.asPrimitive().getTypeName();
}
- } else if (frameType.isUninitializedObject()) {
+ } else if (frameType.isUninitialized()) {
if (frameType.isUninitializedNew()) {
DexType uninitializedNewType = frameType.getUninitializedNewType();
if (uninitializedNewType != null) {
@@ -117,12 +119,23 @@
}
@Override
+ public CfFrameState checkLocals(AppView<?> appView, CfFrame frame) {
+ return this;
+ }
+
+ @Override
+ public CfFrameState checkStack(AppView<?> appView, CfFrame frame) {
+ return this;
+ }
+
+ @Override
public CfFrameState clear() {
return this;
}
@Override
- public CfFrameState markInitialized(FrameType uninitializedType, DexType initializedType) {
+ public CfFrameState markInitialized(
+ UninitializedFrameType uninitializedType, DexType initializedType) {
return this;
}
@@ -132,7 +145,7 @@
}
@Override
- public CfFrameState pop(BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
+ public CfFrameState pop(BiFunction<CfFrameState, PreciseFrameType, CfFrameState> fn) {
return this;
}
@@ -146,7 +159,7 @@
public CfFrameState popInitialized(
AppView<?> appView,
DexType expectedType,
- BiFunction<CfFrameState, FrameType, CfFrameState> fn) {
+ BiFunction<CfFrameState, PreciseFrameType, CfFrameState> fn) {
return this;
}
@@ -161,7 +174,7 @@
}
@Override
- public CfFrameState push(CfAnalysisConfig config, FrameType frameType) {
+ public CfFrameState push(CfAnalysisConfig config, PreciseFrameType frameType) {
return this;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracing.java b/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracing.java
index 046931d..78abb50 100644
--- a/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracing.java
+++ b/src/main/java/com/android/tools/r8/shaking/EnqueuerDeferredTracing.java
@@ -25,7 +25,9 @@
return empty();
}
InternalOptions options = appView.options();
- if (!options.isOptimizing() || !options.isShrinking()) {
+ if (!options.isOptimizing()
+ || !options.isShrinking()
+ || !options.enableEnqueuerDeferredTracing) {
return empty();
}
return new EnqueuerDeferredTracingImpl(appView, enqueuer, mode);
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 5aa62c3..b5898c5 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -1157,6 +1157,20 @@
add(virtualMethods, shadowedBy, MethodSignatureEquivalence.get());
}
+ // Copy over any keep info from the original virtual method.
+ ProgramMethod programMethod = new ProgramMethod(target, shadowedBy);
+ appView
+ .getKeepInfo()
+ .mutate(
+ mutableKeepInfoCollection ->
+ mutableKeepInfoCollection.joinMethod(
+ programMethod,
+ info ->
+ info.merge(
+ mutableKeepInfoCollection
+ .getMethodInfo(virtualMethod, source)
+ .joiner())));
+
deferredRenamings.map(virtualMethod.getReference(), shadowedBy.getReference());
deferredRenamings.recordMove(
virtualMethod.getReference(),
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index ffba372..e3d52a4 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -62,6 +62,21 @@
public class SyntheticItems implements SyntheticDefinitionsProvider {
+ public boolean isSyntheticClassEligibleForMerging(DexProgramClass clazz) {
+ SyntheticDefinition<?, ?, ?> definition = pending.definitions.get(clazz.type);
+ if (definition != null) {
+ return definition.getKind().isShareable();
+ }
+ Iterable<SyntheticReference<?, ?, ?>> references = committed.getItems(clazz.type);
+ Iterator<SyntheticReference<?, ?, ?>> iterator = references.iterator();
+ if (iterator.hasNext()) {
+ boolean sharable = iterator.next().getKind().isShareable();
+ assert Iterables.all(references, r -> sharable == r.getKind().isShareable());
+ return sharable;
+ }
+ return false;
+ }
+
public interface GlobalSyntheticsStrategy {
ContextsForGlobalSynthetics getStrategy();
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 95120b2..f3b82e4d 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -391,6 +391,10 @@
public boolean createSingletonsForStatelessLambdas =
System.getProperty("com.android.tools.r8.createSingletonsForStatelessLambdas") != null;
+ // Flag to allow nest annotations in DEX. See b/231930852 for context.
+ public boolean emitNestAnnotationsInDex =
+ System.getProperty("com.android.tools.r8.emitNestAnnotationsInDex") != null;
+
// Contain the contents of the build properties file from the compiler command.
public DumpOptions dumpOptions;
@@ -607,6 +611,9 @@
// public boolean lookupLibraryBeforeProgram =
// System.getProperty("com.android.tools.r8.lookupProgramBeforeLibrary") == null;
+ public boolean enableEnqueuerDeferredTracing =
+ System.getProperty("com.android.tools.r8.disableEnqueuerDeferredTracing") == null;
+
public boolean loadAllClassDefinitions = false;
// Whether or not to check for valid multi-dex builds.
@@ -2016,7 +2023,7 @@
}
public boolean canUseNestBasedAccess() {
- return !isDesugaring();
+ return !isDesugaring() || emitNestAnnotationsInDex;
}
public boolean canUseRecords() {
diff --git a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
index b2b78d1..dcf816e 100644
--- a/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
+++ b/src/test/java/com/android/tools/r8/BackportedMethodListTest.java
@@ -3,11 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
-import static com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase.isJDK11DesugaredLibrary;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -28,7 +28,8 @@
enum Mode {
NO_LIBRARY,
LIBRARY,
- LIBRARY_DESUGAR
+ LIBRARY_DESUGAR,
+ LIBRARY_DESUGAR_11
}
@Parameterized.Parameters(name = "Mode: {0}")
@@ -42,6 +43,16 @@
this.mode = mode;
}
+ private LibraryDesugaringSpecification getLibraryDesugaringSpecification() {
+ if (mode == Mode.LIBRARY_DESUGAR) {
+ return LibraryDesugaringSpecification.JDK8;
+ }
+ if (mode == Mode.LIBRARY_DESUGAR_11) {
+ return LibraryDesugaringSpecification.JDK11;
+ }
+ return null;
+ }
+
private static class ListStringConsumer implements StringConsumer {
List<String> strings = new ArrayList<>();
boolean finished = false;
@@ -71,17 +82,14 @@
// Java 9, 10 and 11 Optional methods which require Android N or library desugaring.
// The methods are not backported in desugared library JDK 11 (already present).
assertEquals(
- (mode == Mode.LIBRARY_DESUGAR && !isJDK11DesugaredLibrary())
- || apiLevel >= AndroidApiLevel.N.getLevel(),
+ (mode == Mode.LIBRARY_DESUGAR) || apiLevel >= AndroidApiLevel.N.getLevel(),
backports.contains(
"java/util/Optional#or(Ljava/util/function/Supplier;)Ljava/util/Optional;"));
assertEquals(
- (mode == Mode.LIBRARY_DESUGAR && !isJDK11DesugaredLibrary())
- || apiLevel >= AndroidApiLevel.N.getLevel(),
+ (mode == Mode.LIBRARY_DESUGAR) || apiLevel >= AndroidApiLevel.N.getLevel(),
backports.contains("java/util/OptionalInt#orElseThrow()I"));
assertEquals(
- (mode == Mode.LIBRARY_DESUGAR && !isJDK11DesugaredLibrary())
- || apiLevel >= AndroidApiLevel.N.getLevel(),
+ (mode == Mode.LIBRARY_DESUGAR) || apiLevel >= AndroidApiLevel.N.getLevel(),
backports.contains("java/util/OptionalLong#isEmpty()Z"));
// Java 9, 10 and 11 method added at API level S.
@@ -103,8 +111,8 @@
private void addLibraryDesugaring(BackportedMethodListCommand.Builder builder) {
builder
.addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.R.getLevel()));
+ StringResource.fromFile(getLibraryDesugaringSpecification().getSpecification()))
+ .addLibraryFiles(getLibraryDesugaringSpecification().getLibraryFiles());
}
@Test
@@ -115,7 +123,7 @@
BackportedMethodListCommand.builder().setMinApiLevel(apiLevel).setConsumer(consumer);
if (mode == Mode.LIBRARY) {
builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P.getLevel()));
- } else if (mode == Mode.LIBRARY_DESUGAR) {
+ } else if (mode == Mode.LIBRARY_DESUGAR || mode == Mode.LIBRARY_DESUGAR_11) {
addLibraryDesugaring(builder);
}
BackportedMethodList.run(builder.build());
@@ -132,7 +140,7 @@
BackportedMethodListCommand.builder().setMinApiLevel(apiLevel).setOutputPath(output);
if (mode == Mode.LIBRARY) {
builder.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P.getLevel()));
- } else if (mode == Mode.LIBRARY_DESUGAR) {
+ } else if (mode == Mode.LIBRARY_DESUGAR || mode == Mode.LIBRARY_DESUGAR_11) {
addLibraryDesugaring(builder);
}
BackportedMethodList.run(builder.build());
@@ -152,13 +160,13 @@
@Test
public void requireLibraryForDesugar() {
- Assume.assumeTrue(mode == Mode.LIBRARY_DESUGAR);
+ Assume.assumeTrue(mode == Mode.LIBRARY_DESUGAR || mode == Mode.LIBRARY_DESUGAR_11);
// Require library when a desugar configuration is passed.
try {
BackportedMethodList.run(
BackportedMethodListCommand.builder()
.addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
+ StringResource.fromFile(getLibraryDesugaringSpecification().getSpecification()))
.setConsumer(new ListStringConsumer())
.build());
fail("Expected failure");
diff --git a/src/test/java/com/android/tools/r8/CommandTestBase.java b/src/test/java/com/android/tools/r8/CommandTestBase.java
index 733fb9a..1c0c588 100644
--- a/src/test/java/com/android/tools/r8/CommandTestBase.java
+++ b/src/test/java/com/android/tools/r8/CommandTestBase.java
@@ -7,8 +7,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.specificationconversion.AppForSpecConversion;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
@@ -311,11 +311,12 @@
protected InternalOptions getOptionsWithLoadedDesugaredLibraryConfiguration(
C command, boolean libraryCompilation) throws IOException {
InternalOptions options = command.getInternalOptions();
+ LibraryDesugaringSpecification spec = LibraryDesugaringSpecification.JDK11;
options.loadMachineDesugaredLibrarySpecification(
Timing.empty(),
AppForSpecConversion.readAppForTesting(
- libraryCompilation ? ToolHelper.getDesugarJDKLibs() : null,
- ToolHelper.getAndroidJar(AndroidApiLevel.R),
+ libraryCompilation ? spec.getDesugarJdkLibs() : null,
+ spec.getLibraryFiles(),
options,
libraryCompilation,
Timing.empty()));
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index 1ec4d18..d14b01f 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -6,9 +6,7 @@
import com.android.tools.r8.D8Command.Builder;
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.benchmarks.BenchmarkResults;
-import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase.KeepRuleConsumer;
import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import java.nio.file.Path;
@@ -90,15 +88,6 @@
return self();
}
- @Override
- public D8TestBuilder enableCoreLibraryDesugaring(
- AndroidApiLevel minApiLevel,
- KeepRuleConsumer keepRuleConsumer,
- StringResource desugaredLibrarySpecification) {
- super.enableCoreLibraryDesugaring(minApiLevel, keepRuleConsumer, desugaredLibrarySpecification);
- return self();
- }
-
public D8TestBuilder addMainDexRulesFiles(Path... mainDexRuleFiles) {
builder.addMainDexRulesFiles(mainDexRuleFiles);
return self();
diff --git a/src/test/java/com/android/tools/r8/L8CommandTest.java b/src/test/java/com/android/tools/r8/L8CommandTest.java
index dbc7ebd..3526d0c 100644
--- a/src/test/java/com/android/tools/r8/L8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/L8CommandTest.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static com.android.tools.r8.MarkerMatcher.assertMarkersMatch;
import static com.android.tools.r8.MarkerMatcher.markerTool;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -15,11 +16,11 @@
import com.android.tools.r8.AssertionsConfiguration.AssertionTransformationScope;
import com.android.tools.r8.StringConsumer.FileConsumer;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.origin.EmbeddedOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ThreadUtils;
@@ -41,19 +42,27 @@
@RunWith(Parameterized.class)
public class L8CommandTest extends CommandTestBase<L8Command> {
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withNoneRuntime().build();
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(getTestParameters().withNoneRuntime().build(), getJdk8Jdk11());
}
- public L8CommandTest(TestParameters parameters) {
+ public L8CommandTest(
+ TestParameters parameters, LibraryDesugaringSpecification libraryDesugaringSpecification) {
parameters.assertNoneRuntime();
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
}
protected final Matcher<Diagnostic> cfL8NotSupportedDiagnostic =
diagnosticMessage(
containsString("L8 does not support shrinking when generating class files"));
+ private StringResource getDesugaredLibraryConfiguration() {
+ return StringResource.fromFile(libraryDesugaringSpecification.getSpecification());
+ }
+
@Test(expected = CompilationFailedException.class)
public void emptyBuilder() throws Throwable {
verifyEmptyCommand(L8Command.builder().build());
@@ -64,8 +73,7 @@
verifyEmptyCommand(
L8Command.builder()
.setProgramConsumer(DexIndexedConsumer.emptyConsumer())
- .addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
+ .addDesugaredLibraryConfiguration(getDesugaredLibraryConfiguration())
.build());
}
@@ -82,11 +90,10 @@
Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
L8.run(
L8Command.builder()
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
- .addProgramFiles(ToolHelper.getDesugarJDKLibs())
+ .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
+ .addProgramFiles(libraryDesugaringSpecification.getDesugarJdkLibs())
.setMinApiLevel(20)
- .addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
+ .addDesugaredLibraryConfiguration(getDesugaredLibraryConfiguration())
.setOutput(output, OutputMode.DexIndexed)
.build());
assertMarkersMatch(
@@ -99,30 +106,38 @@
Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
L8.run(
L8Command.builder()
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
- .addProgramFiles(ToolHelper.getDesugarJDKLibs())
+ .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
+ .addProgramFiles(libraryDesugaringSpecification.getDesugarJdkLibs())
.setMinApiLevel(20)
- .addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
+ .addDesugaredLibraryConfiguration(getDesugaredLibraryConfiguration())
.setOutput(output, OutputMode.ClassFile)
.build());
assertMarkersMatch(ExtractMarker.extractMarkerFromDexFile(output), markerTool(Tool.L8));
}
+ private List<String> buildCommand(int minAPI, Path output) {
+ ArrayList<String> command = new ArrayList<>();
+ for (Path desugarJDKLib : libraryDesugaringSpecification.getDesugarJdkLibs()) {
+ command.add(desugarJDKLib.toString());
+ }
+ for (Path libraryFile : libraryDesugaringSpecification.getLibraryFiles()) {
+ command.add("--lib");
+ command.add(libraryFile.toString());
+ }
+ command.add("--min-api");
+ command.add(Integer.toString(minAPI));
+ command.add("--desugared-lib");
+ command.add(libraryDesugaringSpecification.getSpecification().toString());
+ command.add("--output");
+ command.add(output.toString());
+ return command;
+ }
+
@Test
public void testDexMarkerCommandLine() throws Throwable {
Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
- L8Command l8Command =
- parse(
- ToolHelper.getDesugarJDKLibs().toString(),
- "--lib",
- ToolHelper.getAndroidJar(AndroidApiLevel.P).toString(),
- "--min-api",
- "20",
- "--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString(),
- "--output",
- output.toString());
+ List<String> command = buildCommand(20, output);
+ L8Command l8Command = parse(command.toArray(new String[0]));
L8.run(l8Command);
assertMarkersMatch(
ExtractMarker.extractMarkerFromDexFile(output),
@@ -132,18 +147,9 @@
@Test
public void testClassFileMarkerCommandLine() throws Throwable {
Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
- L8Command l8Command =
- parse(
- ToolHelper.getDesugarJDKLibs().toString(),
- "--lib",
- ToolHelper.getAndroidJar(AndroidApiLevel.P).toString(),
- "--min-api",
- "20",
- "--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString(),
- "--output",
- output.toString(),
- "--classfile");
+ List<String> command = buildCommand(20, output);
+ command.add("--classfile");
+ L8Command l8Command = parse(command.toArray(new String[0]));
L8.run(l8Command);
assertMarkersMatch(ExtractMarker.extractMarkerFromDexFile(output), markerTool(Tool.L8));
}
@@ -156,7 +162,7 @@
parse(
diagnostics,
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString(),
+ libraryDesugaringSpecification.getSpecification().toString(),
"--pg-conf",
pgconf.toString());
}
@@ -171,7 +177,7 @@
parse(
diagnostics,
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString(),
+ libraryDesugaringSpecification.getSpecification().toString(),
"--pg-conf",
pgconf.toString(),
"--pg-map-output",
@@ -193,7 +199,7 @@
parse(
diagnostics,
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString(),
+ libraryDesugaringSpecification.getSpecification().toString(),
"--pg-conf",
pgconf.toString(),
"--classfile");
@@ -210,7 +216,7 @@
parse(
diagnostics,
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString(),
+ libraryDesugaringSpecification.getSpecification().toString(),
"--pg-conf");
fail("Expected parse error");
} catch (CompilationFailedException e) {
@@ -220,8 +226,8 @@
private L8Command.Builder prepareBuilder(DiagnosticsHandler handler) {
return L8Command.builder(handler)
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
- .addProgramFiles(ToolHelper.getDesugarJDKLibs())
+ .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
+ .addProgramFiles(libraryDesugaringSpecification.getDesugarJdkLibs())
.setMinApiLevel(20);
}
@@ -286,8 +292,7 @@
L8Command.Builder builder =
prepareBuilder(diagnostics)
.setProgramConsumer(programConsumer)
- .addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
+ .addDesugaredLibraryConfiguration(getDesugaredLibraryConfiguration())
.addProguardConfiguration(keepRules, Origin.unknown());
assertTrue(builder.isShrinking());
assertNotNull(builder.build().getR8Command());
@@ -319,8 +324,7 @@
L8Command.Builder builder1 =
prepareBuilder(diagnostics)
.setProgramConsumer(programConsumer)
- .addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
+ .addDesugaredLibraryConfiguration(getDesugaredLibraryConfiguration())
.addProguardConfigurationFiles(keepRuleFile);
assertTrue(builder1.isShrinking());
assertNotNull(builder1.build().getR8Command());
@@ -330,8 +334,7 @@
L8Command.Builder builder2 =
prepareBuilder(new TestDiagnosticMessagesImpl())
.setProgramConsumer(DexIndexedConsumer.emptyConsumer())
- .addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
+ .addDesugaredLibraryConfiguration(getDesugaredLibraryConfiguration())
.addProguardConfigurationFiles(keepRuleFiles);
assertTrue(builder2.isShrinking());
assertNotNull(builder2.build().getR8Command());
@@ -356,12 +359,14 @@
@Test
public void desugaredLibrary() throws CompilationFailedException, IOException {
- L8Command l8Command =
- parse(
- "--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString(),
- "--lib",
- ToolHelper.getAndroidJar(AndroidApiLevel.R).toString());
+ ArrayList<String> command = new ArrayList<>();
+ command.add("--desugared-lib");
+ command.add(libraryDesugaringSpecification.getSpecification().toString());
+ for (Path libraryFile : libraryDesugaringSpecification.getLibraryFiles()) {
+ command.add("--lib");
+ command.add(libraryFile.toString());
+ }
+ L8Command l8Command = parse(command.toArray(new String[0]));
InternalOptions options = getOptionsWithLoadedDesugaredLibraryConfiguration(l8Command, true);
assertFalse(options.machineDesugaredLibrarySpecification.getRewriteType().isEmpty());
}
@@ -403,21 +408,21 @@
parse(
"--force-enable-assertions",
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString())
+ libraryDesugaringSpecification.getSpecification().toString())
.getAssertionsConfiguration(),
AssertionsConfiguration::isCompileTimeEnabled);
checkSingleForceAllAssertion(
parse(
"--force-disable-assertions",
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString())
+ libraryDesugaringSpecification.getSpecification().toString())
.getAssertionsConfiguration(),
AssertionsConfiguration::isCompileTimeDisabled);
checkSingleForceAllAssertion(
parse(
"--force-passthrough-assertions",
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString())
+ libraryDesugaringSpecification.getSpecification().toString())
.getAssertionsConfiguration(),
AssertionsConfiguration::isPassthrough);
checkSingleForceClassAndPackageAssertion(
@@ -425,7 +430,7 @@
"--force-enable-assertions:ClassName",
"--force-enable-assertions:PackageName...",
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString())
+ libraryDesugaringSpecification.getSpecification().toString())
.getAssertionsConfiguration(),
AssertionsConfiguration::isCompileTimeEnabled);
checkSingleForceClassAndPackageAssertion(
@@ -433,7 +438,7 @@
"--force-disable-assertions:ClassName",
"--force-disable-assertions:PackageName...",
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString())
+ libraryDesugaringSpecification.getSpecification().toString())
.getAssertionsConfiguration(),
AssertionsConfiguration::isCompileTimeDisabled);
checkSingleForceClassAndPackageAssertion(
@@ -441,14 +446,14 @@
"--force-passthrough-assertions:ClassName",
"--force-passthrough-assertions:PackageName...",
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString())
+ libraryDesugaringSpecification.getSpecification().toString())
.getAssertionsConfiguration(),
AssertionsConfiguration::isPassthrough);
checkSingleForceAllAssertion(
parse(
"--force-assertions-handler:com.example.MyHandler.handler",
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString())
+ libraryDesugaringSpecification.getSpecification().toString())
.getAssertionsConfiguration(),
configuration ->
configuration.isAssertionHandler()
@@ -466,7 +471,7 @@
"--force-assertions-handler:com.example.MyHandler.handler1:ClassName",
"--force-assertions-handler:com.example.MyHandler.handler2:PackageName...",
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString())
+ libraryDesugaringSpecification.getSpecification().toString())
.getAssertionsConfiguration(),
configuration ->
configuration.isAssertionHandler()
@@ -496,7 +501,7 @@
public void numThreadsOption() throws Exception {
assertEquals(
ThreadUtils.NOT_SPECIFIED,
- parse("--desugared-lib", ToolHelper.getDesugarLibJsonForTesting().toString())
+ parse("--desugared-lib", libraryDesugaringSpecification.getSpecification().toString())
.getThreadCount());
assertEquals(
1,
@@ -504,7 +509,7 @@
"--thread-count",
"1",
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString())
+ libraryDesugaringSpecification.getSpecification().toString())
.getThreadCount());
assertEquals(
2,
@@ -512,7 +517,7 @@
"--thread-count",
"2",
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString())
+ libraryDesugaringSpecification.getSpecification().toString())
.getThreadCount());
assertEquals(
10,
@@ -520,7 +525,7 @@
"--thread-count",
"10",
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString())
+ libraryDesugaringSpecification.getSpecification().toString())
.getThreadCount());
}
@@ -535,7 +540,7 @@
"--thread-count",
value,
"--desugared-lib",
- ToolHelper.getDesugarLibJsonForTesting().toString()));
+ libraryDesugaringSpecification.getSpecification().toString()));
fail("Expected failure");
} catch (CompilationFailedException e) {
// Expected.
@@ -551,7 +556,9 @@
@Override
String[] requiredArgsForTest() {
- return new String[] {"--desugared-lib", ToolHelper.getDesugarLibJsonForTesting().toString()};
+ return new String[] {
+ "--desugared-lib", libraryDesugaringSpecification.getSpecification().toString()
+ };
}
@Override
diff --git a/src/test/java/com/android/tools/r8/MarkersTest.java b/src/test/java/com/android/tools/r8/MarkersTest.java
index 758b061..d5a61db 100644
--- a/src/test/java/com/android/tools/r8/MarkersTest.java
+++ b/src/test/java/com/android/tools/r8/MarkersTest.java
@@ -14,12 +14,15 @@
import static com.android.tools.r8.MarkerMatcher.markerMinApi;
import static com.android.tools.r8.MarkerMatcher.markerR8Mode;
import static com.android.tools.r8.MarkerMatcher.markerTool;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
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.dex.Marker;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.origin.Origin;
@@ -41,27 +44,27 @@
public class MarkersTest extends DesugaredLibraryTestBase {
@Parameterized.Parameters(
- name = "{0}, compilationMode {1}, shrinkDesugaredLibrary {2}, noCfMarkerForDesugaredCode {3}")
+ name = "{0}, spec: {1}, compilationMode {2}, {3}, noCfMarkerForDesugaredCode {4}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withNoneRuntime().build(),
- CompilationMode.values(),
- BooleanUtils.values(),
+ LibraryDesugaringSpecification.getJdk8Jdk11(),
+ DEFAULT_SPECIFICATIONS,
BooleanUtils.values());
}
- private final CompilationMode compilationMode;
- private final boolean shrinkDesugaredLibrary;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
private final boolean noCfMarkerForDesugaredCode;
public MarkersTest(
TestParameters parameters,
- CompilationMode compilationMode,
- boolean shrinkDesugaredLibrary,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification,
boolean noCfMarkerForDesugaredCode) {
parameters.assertNoneRuntime();
- this.compilationMode = compilationMode;
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
this.noCfMarkerForDesugaredCode = noCfMarkerForDesugaredCode;
}
@@ -72,24 +75,27 @@
AndroidApiLevel apiLevel = AndroidApiLevel.L;
Path output = temp.newFolder().toPath().resolve("desugar_jdk_libs.zip");
+ CompilationMode compilationMode =
+ compilationSpecification.isL8Shrink() ? CompilationMode.RELEASE : CompilationMode.DEBUG;
L8Command.Builder builder =
L8Command.builder()
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
- .addProgramFiles(ToolHelper.getDesugarJDKLibs())
- .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
+ .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
+ .addProgramFiles(libraryDesugaringSpecification.getDesugarJdkLibs())
.setMinApiLevel(apiLevel.getLevel())
.setMode(compilationMode)
.addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
+ StringResource.fromFile(libraryDesugaringSpecification.getSpecification()))
.setOutput(output, OutputMode.DexIndexed);
- if (shrinkDesugaredLibrary) {
+ if (compilationSpecification.isL8Shrink()) {
builder.addProguardConfiguration(ImmutableList.of("-keep class * { *; }"), Origin.unknown());
}
L8.run(builder.build());
Collection<Marker> markers = ExtractMarker.extractMarkerFromDexFile(output);
JsonObject jsonObject =
new JsonParser()
- .parse(FileUtils.readTextFile(ToolHelper.getDesugarLibJsonForTesting(), Charsets.UTF_8))
+ .parse(
+ FileUtils.readTextFile(
+ libraryDesugaringSpecification.getSpecification(), Charsets.UTF_8))
.getAsJsonObject();
String identifier =
jsonObject.has("version")
@@ -111,7 +117,8 @@
Matcher<Marker> d8Matcher =
allOf(markerTool(Tool.D8), markerCompilationMode(compilationMode), markerMinApi(apiLevel));
assertMarkersMatch(
- markers, ImmutableList.of(l8Matcher, shrinkDesugaredLibrary ? r8Matcher : d8Matcher));
+ markers,
+ ImmutableList.of(l8Matcher, compilationSpecification.isL8Shrink() ? r8Matcher : d8Matcher));
}
@Test
@@ -122,7 +129,7 @@
D8Command.builder()
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class))
- .setMode(compilationMode)
+ .setMode(compilationSpecification.getProgramCompilationMode())
.setMinApiLevel(apiLevel.getLevel())
.setOutput(output, OutputMode.DexIndexed);
if (noCfMarkerForDesugaredCode) {
@@ -135,7 +142,7 @@
Matcher<Marker> matcher =
allOf(
markerTool(Tool.D8),
- markerCompilationMode(compilationMode),
+ markerCompilationMode(compilationSpecification.getProgramCompilationMode()),
markerBackend(Backend.DEX),
markerIsDesugared(),
markerMinApi(apiLevel),
@@ -146,7 +153,7 @@
@Test
public void testD8MarkerInCf() throws Throwable {
// Shrinking of desugared library is not affecting this test.
- assumeTrue(shrinkDesugaredLibrary);
+ assumeTrue(compilationSpecification.isL8Shrink());
AndroidApiLevel apiLevel = AndroidApiLevel.L;
Path output = temp.newFolder().toPath().resolve("output.zip");
@@ -154,7 +161,7 @@
D8Command.builder()
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class))
- .setMode(compilationMode)
+ .setMode(compilationSpecification.getProgramCompilationMode())
.setMinApiLevel(apiLevel.getLevel())
.setOutput(output, OutputMode.ClassFile);
if (noCfMarkerForDesugaredCode) {
@@ -168,7 +175,7 @@
Matcher<Marker> matcher =
allOf(
markerTool(Tool.D8),
- markerCompilationMode(compilationMode),
+ markerCompilationMode(compilationSpecification.getProgramCompilationMode()),
markerBackend(Backend.CF),
markerIsDesugared(),
markerMinApi(apiLevel),
@@ -180,7 +187,7 @@
@Test
public void testR8MarkerInDex() throws Throwable {
// Shrinking of desugared library is not affecting this test.
- assumeTrue(shrinkDesugaredLibrary);
+ assumeTrue(compilationSpecification.isL8Shrink());
AndroidApiLevel apiLevel = AndroidApiLevel.L;
Path output = temp.newFolder().toPath().resolve("output.zip");
@@ -189,7 +196,7 @@
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class))
.addProguardConfiguration(ImmutableList.of("-keep class * { *; }"), Origin.unknown())
- .setMode(compilationMode)
+ .setMode(compilationSpecification.getProgramCompilationMode())
.setMinApiLevel(apiLevel.getLevel())
.setOutput(output, OutputMode.DexIndexed);
if (noCfMarkerForDesugaredCode) {
@@ -203,7 +210,7 @@
Matcher<Marker> matcher =
allOf(
markerTool(Tool.R8),
- markerCompilationMode(compilationMode),
+ markerCompilationMode(compilationSpecification.getProgramCompilationMode()),
markerBackend(Backend.DEX),
markerIsDesugared(),
markerMinApi(apiLevel),
@@ -214,7 +221,7 @@
@Test
public void testR8MarkerInCf() throws Throwable {
// Shrinking of desugared library is not affecting this test.
- assumeTrue(shrinkDesugaredLibrary);
+ assumeTrue(compilationSpecification.isL8Shrink());
Path output = temp.newFolder().toPath().resolve("output.zip");
R8Command.Builder builder =
@@ -222,7 +229,7 @@
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class))
.addProguardConfiguration(ImmutableList.of("-keep class * { *; }"), Origin.unknown())
- .setMode(compilationMode)
+ .setMode(compilationSpecification.getProgramCompilationMode())
.setOutput(output, OutputMode.ClassFile);
if (noCfMarkerForDesugaredCode) {
ToolHelper.runR8(
@@ -235,7 +242,7 @@
Matcher<Marker> matcher =
allOf(
markerTool(Tool.R8),
- markerCompilationMode(compilationMode),
+ markerCompilationMode(compilationSpecification.getProgramCompilationMode()),
markerBackend(Backend.CF),
not(markerIsDesugared()),
not(markerHasMinApi()),
@@ -246,7 +253,7 @@
@Test
public void testR8MarkerInCfAfterD8CfDesugar() throws Throwable {
// Shrinking of desugared library is not affecting this test.
- assumeTrue(shrinkDesugaredLibrary);
+ assumeTrue(compilationSpecification.isL8Shrink());
AndroidApiLevel apiLevel = AndroidApiLevel.L;
Path d8DesugaredOutput = temp.newFolder().toPath().resolve("output.zip");
@@ -254,7 +261,7 @@
D8Command.builder()
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class))
- .setMode(compilationMode)
+ .setMode(compilationSpecification.getProgramCompilationMode())
.setMinApiLevel(apiLevel.getLevel())
.setOutput(d8DesugaredOutput, OutputMode.ClassFile);
if (noCfMarkerForDesugaredCode) {
@@ -268,7 +275,7 @@
ExtractMarker.extractMarkerFromDexFile(d8DesugaredOutput),
allOf(
markerTool(Tool.D8),
- markerCompilationMode(compilationMode),
+ markerCompilationMode(compilationSpecification.getProgramCompilationMode()),
markerIsDesugared(),
markerMinApi(apiLevel),
not(markerHasDesugaredLibraryIdentifier())));
@@ -281,14 +288,14 @@
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
.addProgramFiles(ToolHelper.getClassFileForTestClass(TestClass.class))
.addProguardConfiguration(ImmutableList.of("-keep class * { *; }"), Origin.unknown())
- .setMode(compilationMode)
+ .setMode(compilationSpecification.getProgramCompilationMode())
.setOutput(output, OutputMode.ClassFile)
.build());
assertMarkersMatch(
ExtractMarker.extractMarkerFromDexFile(output),
allOf(
markerTool(Tool.R8),
- markerCompilationMode(compilationMode),
+ markerCompilationMode(compilationSpecification.getProgramCompilationMode()),
markerBackend(Backend.CF),
not(markerIsDesugared()),
not(markerHasMinApi()),
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 10bc820..ff90c43 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -696,15 +696,6 @@
return enableProguardTestOptions();
}
- @Override
- public T enableCoreLibraryDesugaring(
- AndroidApiLevel minApiLevel,
- KeepRuleConsumer keepRuleConsumer,
- StringResource desugaredLibrarySpecification) {
- super.enableCoreLibraryDesugaring(minApiLevel, keepRuleConsumer, desugaredLibrarySpecification);
- return self();
- }
-
public T addFeatureSplitRuntime() {
addProgramClasses(SplitRunner.class, RunInterface.class);
addKeepClassAndMembersRules(SplitRunner.class, RunInterface.class);
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index ead3195..d7a6cc2 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -494,43 +494,11 @@
return allowStderrMessages();
}
- public T enableCoreLibraryDesugaring(
- AndroidApiLevel minApiLevel, KeepRuleConsumer keepRuleConsumer) {
- return enableCoreLibraryDesugaring(
- minApiLevel,
- keepRuleConsumer,
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
- }
-
public T enableCoreLibraryDesugaring(LibraryDesugaringTestConfiguration configuration) {
this.libraryDesugaringTestConfiguration = configuration;
return self();
}
- public T enableCoreLibraryDesugaring(
- AndroidApiLevel minApiLevel,
- KeepRuleConsumer keepRuleConsumer,
- StringResource desugaredLibrarySpecification) {
- return enableLibraryDesugaring(
- LibraryDesugaringTestConfiguration.builder()
- .setMinApi(minApiLevel)
- .setKeepRuleConsumer(keepRuleConsumer)
- .addDesugaredLibraryConfiguration(desugaredLibrarySpecification)
- .dontAddRunClasspath()
- .build());
- }
-
- public T enableLibraryDesugaring(AndroidApiLevel minApiLevel) {
- this.libraryDesugaringTestConfiguration =
- LibraryDesugaringTestConfiguration.builder().setMinApi(minApiLevel).build();
- return self();
- }
-
- public T enableLibraryDesugaring(LibraryDesugaringTestConfiguration configuration) {
- this.libraryDesugaringTestConfiguration = configuration;
- return self();
- }
-
@Override
public T addRunClasspathFiles(Collection<Path> files) {
additionalRunClassPath.addAll(files);
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index bc5f2e4..e7c64cd 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -184,7 +184,7 @@
OPEN_JDK_DIR + "desugar_jdk_libs_releases/";
public static final Path DESUGARED_JDK_8_LIB_JAR =
Paths.get(OPEN_JDK_DIR + "desugar_jdk_libs/desugar_jdk_libs.jar");
- public static final Path DESUGARED_JDK_11_LIB_JAR =
+ public static final Path UNDESUGARED_JDK_11_LIB_JAR =
DesugaredLibraryJDK11Undesugarer.undesugaredJarJDK11(
Paths.get(OPEN_JDK_DIR + "desugar_jdk_libs_11/desugar_jdk_libs.jar"));
@@ -204,26 +204,10 @@
return System.getProperty("desugar_jdk_json_dir", "src/library_desugar");
}
- public static Path getDesugarLibJsonMinimalForTesting() {
- return Paths.get(getDesugarLibraryJsonDir(), "desugar_jdk_libs_minimal.json");
- }
-
public static Path getDesugarLibJsonForTesting() {
return Paths.get(getDesugarLibraryJsonDir(), "desugar_jdk_libs.json");
}
- public static Path getDesugarLibJsonForTestingWithPath() {
- return Paths.get(getDesugarLibraryJsonDir(), "desugar_jdk_libs_path.json");
- }
-
- public static Path getCHMOnlyDesugarLibJsonForTesting() {
- return Paths.get(getDesugarLibraryJsonDir(), "chm_only_desugar_jdk_libs.json");
- }
-
- public static Path getDesugarLibJsonForTestingAlternative3() {
- return Paths.get(getDesugarLibraryJsonDir(), "desugar_jdk_libs_path_alternative_3.json");
- }
-
public static boolean isLocalDevelopment() {
return System.getProperty("local_development", "0").equals("1");
}
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest.java
index dc66150..9ff8a9b 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelDesugaredLibraryReferenceTest.java
@@ -4,12 +4,17 @@
package com.android.tools.r8.apimodel;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.R8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.R8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static org.junit.Assert.assertEquals;
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.references.Reference;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.google.common.collect.ImmutableList;
import java.lang.reflect.Method;
import java.time.Clock;
import java.util.List;
@@ -22,45 +27,43 @@
public class ApiModelDesugaredLibraryReferenceTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
- private final boolean shrinkDesugaredLibrary;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameters(name = "{0}, shrinkDesugaredLibrary: {1}")
+ @Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
return buildParameters(
- getTestParameters().withDexRuntimes().withAllApiLevels().build(), BooleanUtils.values());
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ ImmutableList.of(R8_L8DEBUG, R8_L8SHRINK));
}
public ApiModelDesugaredLibraryReferenceTest(
- TestParameters parameters, boolean shrinkDesugaredLibrary) {
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
- public void testClockR8() throws Exception {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+ public void testClock() throws Throwable {
Method printZone = DesugaredLibUser.class.getDeclaredMethod("printZone");
Method main = Executor.class.getDeclaredMethod("main", String[].class);
- testForR8(parameters.getBackend())
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
.addProgramClasses(Executor.class, DesugaredLibUser.class)
- .addLibraryFiles(getLibraryFile())
.addKeepMainRule(Executor.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .apply(ApiModelingTestHelper::enableApiCallerIdentification)
- .apply(
- ApiModelingTestHelper.addTracedApiReferenceLevelCallBack(
- (reference, apiLevel) -> {
- if (reference.equals(Reference.methodFromMethod(printZone))) {
- assertEquals(parameters.getApiLevel(), apiLevel);
- }
- }))
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
+ .applyOnBuilder(ApiModelingTestHelper::enableApiCallerIdentification)
+ .applyOnBuilder(
+ b ->
+ ApiModelingTestHelper.addTracedApiReferenceLevelCallBack(
+ (reference, apiLevel) -> {
+ if (reference.equals(Reference.methodFromMethod(printZone))) {
+ assertEquals(parameters.getApiLevel(), apiLevel);
+ }
+ })
+ .acceptWithRuntimeException(b))
.run(parameters.getRuntime(), Executor.class)
.assertSuccessWithOutputLines("Z")
.inspect(
diff --git a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest.java b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest.java
index 0457c25..c0cc0fc 100644
--- a/src/test/java/com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest.java
+++ b/src/test/java/com/android/tools/r8/apimodel/ApiModelNoDesugaredLibraryReferenceTest.java
@@ -5,13 +5,19 @@
package com.android.tools.r8.apimodel;
import static com.android.tools.r8.apimodel.ApiModelingTestHelper.verifyThat;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.R8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.R8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static org.junit.Assert.assertEquals;
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.references.Reference;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
import java.lang.reflect.Method;
import java.nio.file.Paths;
import java.util.List;
@@ -24,40 +30,45 @@
public class ApiModelNoDesugaredLibraryReferenceTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameters(name = "{0}")
+ @Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
- return buildParameters(getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ ImmutableList.of(R8_L8DEBUG, R8_L8SHRINK));
}
- public ApiModelNoDesugaredLibraryReferenceTest(TestParameters parameters) {
+ public ApiModelNoDesugaredLibraryReferenceTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
- public void testR8() throws Exception {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+ public void test() throws Throwable {
Method printZone = LibUser.class.getDeclaredMethod("printPath");
Method main = Executor.class.getDeclaredMethod("main", String[].class);
- testForR8(parameters.getBackend())
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
.addProgramClasses(Executor.class, LibUser.class)
- .addLibraryFiles(getLibraryFile())
.addKeepMainRule(Executor.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .apply(ApiModelingTestHelper::enableApiCallerIdentification)
+ .applyOnBuilder(ApiModelingTestHelper::enableApiCallerIdentification)
// We are testing that we do not inline/merge higher api-levels
- .apply(ApiModelingTestHelper::disableOutliningAndStubbing)
- .apply(
- ApiModelingTestHelper.addTracedApiReferenceLevelCallBack(
- (reference, apiLevel) -> {
- if (reference.equals(Reference.methodFromMethod(printZone))) {
- assertEquals(AndroidApiLevel.O.max(parameters.getApiLevel()), apiLevel);
- }
- }))
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary, parameters.getApiLevel(), keepRuleConsumer.get(), false)
+ .applyOnBuilder(ApiModelingTestHelper::disableOutliningAndStubbing)
+ .applyOnBuilder(
+ b ->
+ ApiModelingTestHelper.addTracedApiReferenceLevelCallBack(
+ (reference, apiLevel) -> {
+ if (reference.equals(Reference.methodFromMethod(printZone))) {
+ assertEquals(AndroidApiLevel.O.max(parameters.getApiLevel()), apiLevel);
+ }
+ })
+ .acceptWithRuntimeException(b))
.run(parameters.getRuntime(), Executor.class)
.applyIf(
parameters.getDexRuntimeVersion().isDalvik(),
diff --git a/src/test/java/com/android/tools/r8/cf/FrameComparisonTest.java b/src/test/java/com/android/tools/r8/cf/FrameComparisonTest.java
index 5207198..095c7c4 100644
--- a/src/test/java/com/android/tools/r8/cf/FrameComparisonTest.java
+++ b/src/test/java/com/android/tools/r8/cf/FrameComparisonTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.cf.code.CfFrame;
-import com.android.tools.r8.cf.code.CfFrame.FrameType;
+import com.android.tools.r8.cf.code.frame.FrameType;
import com.android.tools.r8.graph.DexItemFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
diff --git a/src/test/java/com/android/tools/r8/cf/MethodHandleDifferentNameArgumentPropagationTest.java b/src/test/java/com/android/tools/r8/cf/MethodHandleDifferentNameArgumentPropagationTest.java
new file mode 100644
index 0000000..5106ff8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/MethodHandleDifferentNameArgumentPropagationTest.java
@@ -0,0 +1,74 @@
+// 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 com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import java.util.function.Consumer;
+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;
+
+/* This is a regression for b/231662249 */
+@RunWith(Parameterized.class)
+public class MethodHandleDifferentNameArgumentPropagationTest extends TestBase {
+
+ private static final String[] EXPECTED =
+ new String[] {"ImplementationInstanceMethod::forEachWithOtherName"};
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withCfRuntimes().build();
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ testForJvm()
+ .addInnerClasses(MethodHandleDifferentNameArgumentPropagationTest.class)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(MethodHandleDifferentNameArgumentPropagationTest.class)
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> options.apiModelingOptions().disableApiCallerIdentification())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ public interface Foreachable {
+ void forEach(Consumer<String> consumer);
+ }
+
+ public static class ImplementationInstanceMethod {
+
+ public void forEachWithOtherName(Consumer<String> consumer) {
+ consumer.accept("ImplementationInstanceMethod::forEachWithOtherName");
+ }
+ }
+
+ public static class ImplementationInstanceMethodSub extends ImplementationInstanceMethod {}
+
+ public static class Main {
+
+ public static void test(Foreachable foreachable) {
+ foreachable.forEach(System.out::println);
+ }
+
+ public static void main(String[] args) {
+ ImplementationInstanceMethodSub impl = new ImplementationInstanceMethodSub();
+ test(impl::forEachWithOtherName);
+ }
+ }
+}
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 9fffa07..41c05a3 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
@@ -4,7 +4,6 @@
package com.android.tools.r8.cf.stackmap;
-import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
@@ -13,30 +12,29 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.transformers.ClassFileTransformer.MethodPredicate;
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 InvalidStackHeightTest extends TestBase {
- private final String[] EXPECTED = new String[] {"42"};
+ private static final String[] EXPECTED = new String[] {"42"};
- private final TestParameters parameters;
+ @Parameter(0)
+ public TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
}
- public InvalidStackHeightTest(TestParameters parameters) {
- this.parameters = parameters;
- }
-
@Test
public void smokeTest() throws Exception {
testForRuntime(parameters)
@@ -51,11 +49,7 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(getMainWithChangedMaxStackHeight())
.setMinApi(parameters.getApiLevel())
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertWarningMessageThatMatches(
- containsString("The max stack height of 1 is violated"));
- });
+ .compileWithExpectedDiagnostics(this::inspect);
}
@Test
@@ -64,16 +58,12 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(getMainWithChangedMaxStackHeight())
.setMinApi(parameters.getApiLevel())
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertWarningMessageThatMatches(
- containsString("The max stack height of 1 is violated"));
- })
+ .compileWithExpectedDiagnostics(this::inspect)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines(EXPECTED);
}
- @Test()
+ @Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
.addProgramClassFileData(getMainWithChangedMaxStackHeight())
@@ -81,15 +71,16 @@
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
.allowDiagnosticWarningMessages()
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertWarningsMatch(
- diagnosticMessage(containsString("The max stack height of 1 is violated")));
- })
+ .compileWithExpectedDiagnostics(this::inspect)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines(EXPECTED);
}
+ private void inspect(TestDiagnosticMessages diagnostics) {
+ diagnostics.assertWarningMessageThatMatches(
+ containsString("The max stack height of 1 is violated"));
+ }
+
@Test()
public void testR8InputVerification() throws Exception {
try {
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/StackMapVerificationNoFrameForHandlerTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/StackMapVerificationNoFrameForHandlerTest.java
index 7e8c85c..c3c79fb 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/StackMapVerificationNoFrameForHandlerTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/StackMapVerificationNoFrameForHandlerTest.java
@@ -35,7 +35,7 @@
private final String EXPECTED_JVM_ERROR =
"java.lang.VerifyError: Expecting a stackmap frame at branch target";
- @Parameters(name = "{0}")
+ @Parameters(name = "{0}, include frame in handler: {1}")
public static List<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedGetFieldTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedGetFieldTest.java
index 113a40f..00c3c60 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedGetFieldTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedGetFieldTest.java
@@ -11,11 +11,13 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.FieldVisitor;
@@ -25,18 +27,14 @@
@RunWith(Parameterized.class)
public class UninitializedGetFieldTest extends TestBase {
- private final String[] EXPECTED = new String[] {"Main::foo"};
- private final TestParameters parameters;
+ @Parameter(0)
+ public TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
}
- public UninitializedGetFieldTest(TestParameters parameters) {
- this.parameters = parameters;
- }
-
@Test
public void testJvm() throws Exception {
assumeTrue(parameters.isCfRuntime());
@@ -52,11 +50,7 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(dump())
.setMinApi(parameters.getApiLevel())
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertWarningThatMatches(
- diagnosticMessage(containsString("The expected type uninitialized")));
- });
+ .compileWithExpectedDiagnostics(this::inspect);
}
@Test
@@ -65,15 +59,20 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(dump())
.setMinApi(parameters.getApiLevel())
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertWarningThatMatches(
- diagnosticMessage(containsString("The expected type uninitialized")));
- })
+ .compileWithExpectedDiagnostics(this::inspect)
.run(parameters.getRuntime(), Main.class)
.assertFailureWithErrorThatThrows(VerifyError.class);
}
+ private void inspect(TestDiagnosticMessages diagnostics) {
+ diagnostics.assertWarningThatMatches(
+ diagnosticMessage(
+ containsString(
+ "Expected initialized "
+ + Main.class.getTypeName()
+ + " on stack, but was uninitialized-this")));
+ }
+
public static class Main {
private Object object;
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedInstanceOfTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedInstanceOfTest.java
index 492e21e..9e5411e 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedInstanceOfTest.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRunResult;
@@ -17,6 +18,7 @@
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;
@@ -25,7 +27,8 @@
@RunWith(Parameterized.class)
public class UninitializedInstanceOfTest extends TestBase {
- private final TestParameters parameters;
+ @Parameter(0)
+ public TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
@@ -47,13 +50,7 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(dump())
.setMinApi(parameters.getApiLevel())
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertWarningMessageThatMatches(
- containsString("The expected type uninitialized new is not assignable"));
- diagnostics.assertErrorMessageThatMatches(
- containsString("Could not validate stack map frames"));
- });
+ .compileWithExpectedDiagnostics(this::inspect);
}
@Test()
@@ -63,11 +60,7 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(dump())
.setMinApi(parameters.getApiLevel())
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertWarningMessageThatMatches(
- containsString("The expected type uninitialized new is not assignable"));
- })
+ .compileWithExpectedDiagnostics(this::inspect)
.run(parameters.getRuntime(), Main.class)
.applyIf(
expectFailure,
@@ -75,8 +68,15 @@
TestRunResult::assertSuccessWithOutputLines);
}
- public UninitializedInstanceOfTest(TestParameters parameters) {
- this.parameters = parameters;
+ private void inspect(TestDiagnosticMessages diagnostics) {
+ diagnostics.assertWarningMessageThatMatches(
+ containsString(
+ "Expected initialized java.lang.Object on stack, but was uninitialized"
+ + " java.lang.Object"));
+ if (parameters.isCfRuntime()) {
+ diagnostics.assertErrorMessageThatMatches(
+ containsString("Could not validate stack map frames"));
+ }
}
public static class Main {
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedNewCheckCastTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedNewCheckCastTest.java
index 86429af..669829b 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedNewCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedNewCheckCastTest.java
@@ -10,11 +10,13 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
@@ -23,7 +25,8 @@
@RunWith(Parameterized.class)
public class UninitializedNewCheckCastTest extends TestBase {
- private final TestParameters parameters;
+ @Parameter(0)
+ public TestParameters parameters;
@Parameters(name = "{0}")
public static TestParametersCollection data() {
@@ -45,13 +48,7 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(dump())
.setMinApi(parameters.getApiLevel())
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertWarningMessageThatMatches(
- containsString("The expected type uninitialized new is not assignable"));
- diagnostics.assertErrorMessageThatMatches(
- containsString("Could not validate stack map frames"));
- });
+ .compileWithExpectedDiagnostics(this::inspect);
}
@Test
@@ -60,17 +57,20 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(dump())
.setMinApi(parameters.getApiLevel())
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertWarningMessageThatMatches(
- containsString("The expected type uninitialized new is not assignable"));
- })
+ .compileWithExpectedDiagnostics(this::inspect)
.run(parameters.getRuntime(), Main.class)
.assertFailureWithErrorThatThrows(VerifyError.class);
}
- public UninitializedNewCheckCastTest(TestParameters parameters) {
- this.parameters = parameters;
+ private void inspect(TestDiagnosticMessages diagnostics) {
+ diagnostics.assertWarningMessageThatMatches(
+ containsString(
+ "Expected initialized java.lang.Object on stack, but was uninitialized"
+ + " java.lang.Object"));
+ if (parameters.isCfRuntime()) {
+ diagnostics.assertErrorMessageThatMatches(
+ containsString("Could not validate stack map frames"));
+ }
}
public static class Main {
diff --git a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedPutFieldSelfTest.java b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedPutFieldSelfTest.java
index 9a52445..e4e918b 100644
--- a/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedPutFieldSelfTest.java
+++ b/src/test/java/com/android/tools/r8/cf/stackmap/UninitializedPutFieldSelfTest.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper.DexVm.Version;
@@ -47,13 +48,7 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(dump())
.setMinApi(parameters.getApiLevel())
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertWarningMessageThatMatches(
- containsString("The expected type uninitialized this is not assignable"));
- diagnostics.assertErrorMessageThatMatches(
- containsString("Could not validate stack map frames"));
- });
+ .compileWithExpectedDiagnostics(this::inspect);
}
@Test
@@ -65,16 +60,24 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(dump())
.setMinApi(parameters.getApiLevel())
- .compileWithExpectedDiagnostics(
- diagnostics -> {
- diagnostics.assertWarningMessageThatMatches(
- containsString("The expected type uninitialized this is not assignable"));
- })
+ .compileWithExpectedDiagnostics(this::inspect)
.run(parameters.getRuntime(), Main.class)
.assertFailureWithErrorThatThrowsIf(willFailVerification, VerifyError.class)
.assertSuccessWithOutputLinesIf(!willFailVerification, "Main::foo");
}
+ private void inspect(TestDiagnosticMessages diagnostics) {
+ diagnostics.assertWarningMessageThatMatches(
+ containsString(
+ "Expected initialized "
+ + Main.class.getTypeName()
+ + " on stack, but was uninitialized-this"));
+ if (parameters.isCfRuntime()) {
+ diagnostics.assertErrorMessageThatMatches(
+ containsString("Could not validate stack map frames"));
+ }
+ }
+
public UninitializedPutFieldSelfTest(TestParameters parameters) {
this.parameters = parameters;
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingInD8WithCompanionClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingInD8WithCompanionClassesTest.java
new file mode 100644
index 0000000..d143c60
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingInD8WithCompanionClassesTest.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.classmerging.horizontal;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertNotEquals;
+
+import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+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;
+
+/**
+ * This is a regression test for b/227791663.
+ *
+ * <p>Non-sharable synthetics should not be deduplicated or merged in D8. Examples are the global
+ * synthetics such as RecordTag and API type stubs, but also fixed-suffix synthetics, such as
+ * companion classes for interfaces, which rely on a specific suffix in cases of separate
+ * compilation.
+ */
+@RunWith(Parameterized.class)
+public class HorizontalClassMergingInD8WithCompanionClassesTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ .withDexRuntimes()
+ .withApiLevelsEndingAtExcluding(apiLevelWithDefaultInterfaceMethodsSupport())
+ .build();
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .setMode(CompilationMode.RELEASE)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(
+ options -> {
+ options.horizontalClassMergerOptions().enable();
+ options.horizontalClassMergerOptions().setRestrictToSynthetics();
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("I::foo", "J::bar")
+ .inspect(
+ inspector -> {
+ ClassSubject companionI = inspector.clazz(I.class).toCompanionClass();
+ ClassSubject companionJ = inspector.clazz(J.class).toCompanionClass();
+ assertThat(companionI, isPresent());
+ assertThat(companionJ, isPresent());
+ assertNotEquals(companionI.getFinalName(), companionJ.getFinalName());
+ });
+ }
+
+ public interface I {
+ default void foo() {
+ System.out.println("I::foo");
+ }
+ }
+
+ public interface J {
+ default void bar() {
+ System.out.println("J::bar");
+ }
+ }
+
+ public static class A implements I {}
+
+ public static class B implements J {}
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ new A().foo();
+ new B().bar();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java
index 33bd1a2..1730dc8 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithRetargetedLibMemberTest.java
@@ -4,17 +4,20 @@
package com.android.tools.r8.classmerging.vertical;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.R8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
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.google.common.collect.ImmutableList;
import java.util.Arrays;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -24,29 +27,34 @@
public class ForceInlineConstructorWithRetargetedLibMemberTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return TestBase.getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ ImmutableList.of(R8_L8DEBUG));
}
- public ForceInlineConstructorWithRetargetedLibMemberTest(TestParameters parameters) {
+ public ForceInlineConstructorWithRetargetedLibMemberTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
- public void test() throws Exception {
- // Regression test for b/170677722.
- testForR8(parameters.getBackend())
- .addLibraryFiles(getLibraryFile())
+ public void test() throws Throwable {
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
.addInnerClasses(getClass())
.addKeepMainRule(TestClass.class)
+ .enableNeverClassInliningAnnotations()
.addVerticallyMergedClassesInspector(
inspector -> inspector.assertMergedIntoSubtype(A.class))
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .enableNeverClassInliningAnnotations()
- .setMinApi(parameters.getApiLevel())
.compile()
.inspect(
inspector -> {
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingTypeArgsSubstitutionTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingTypeArgsSubstitutionTest.java
index 4fad79d..d4d1355 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingTypeArgsSubstitutionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithMissingTypeArgsSubstitutionTest.java
@@ -59,17 +59,21 @@
MethodSubject bar = classSubject.uniqueMethodWithName("bar");
assertThat(bar, isPresentAndRenamed());
assertEquals("(TT;)V", bar.getFinalSignatureAttribute());
- // The NeverInline is transferred to the private vertically merged method, making
- // it hard to lookup.
- MethodSubject movedFooSubject =
+ // The NeverInline is transferred to the private vertically merged method but also
+ // copied to the virtual bridge.
+ MethodSubject fooMovedFromB =
classSubject.uniqueMethodThatMatches(
- method ->
- method.getMethod().getReference() != bar.getMethod().getReference()
- && !method.isInstanceInitializer());
- assertThat(movedFooSubject, isPresentAndRenamed());
+ method -> !method.isVirtual() && method.getOriginalName(false).equals("foo"));
+ assertThat(fooMovedFromB, isPresentAndRenamed());
assertEquals(
"(Ljava/lang/Object;)Ljava/lang/Object;",
- movedFooSubject.getFinalSignatureAttribute());
+ fooMovedFromB.getFinalSignatureAttribute());
+ MethodSubject fooBridge =
+ classSubject.uniqueMethodThatMatches(
+ method -> method.isVirtual() && method.getOriginalName(false).equals("foo"));
+ assertThat(fooBridge, isPresentAndRenamed());
+ assertEquals(
+ "(Ljava/lang/Object;)Ljava/lang/Object;", fooBridge.getFinalSignatureAttribute());
});
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithNonVisibleAnnotationTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithNonVisibleAnnotationTest.java
index c3a7cfc..c431ea1 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithNonVisibleAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergingWithNonVisibleAnnotationTest.java
@@ -62,7 +62,10 @@
// Assert that the merged class has no annotations from Base
assertTrue(sub.getDexProgramClass().annotations().isEmpty());
// Assert that foo has the private annotation from the Base.foo
- MethodSubject foo = sub.uniqueMethodWithName("foo");
+ MethodSubject foo =
+ sub.uniqueMethodThatMatches(
+ method ->
+ method.getOriginalName(false).equals("foo") && !method.isSynthetic());
assertThat(foo, isPresent());
AnnotationSubject privateMethodAnnotation =
foo.annotation(
diff --git a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToEmulatedDefaultMethodTest.java b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToEmulatedDefaultMethodTest.java
index 8d914a8..2dd34a5 100644
--- a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToEmulatedDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToEmulatedDefaultMethodTest.java
@@ -3,37 +3,52 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.desugar;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.utils.AndroidApiLevel;
+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 com.google.common.collect.ImmutableList;
import java.util.Collection;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import java.util.Set;
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 InvokeSuperToEmulatedDefaultMethodTest extends DesugaredLibraryTestBase {
private static final String EXPECTED = StringUtils.lines("bar", "bar");
- @Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimesAndApiLevels().build();
+ private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ getJdk8Jdk11(),
+ ImmutableList.of(D8_L8DEBUG));
}
- private final TestParameters parameters;
-
- public InvokeSuperToEmulatedDefaultMethodTest(TestParameters parameters) {
+ public InvokeSuperToEmulatedDefaultMethodTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
private boolean needsDefaultInterfaceMethodDesugaring() {
@@ -43,6 +58,7 @@
@Test
public void testReference() throws Exception {
+ assumeTrue("Run only once", libraryDesugaringSpecification == JDK11);
assumeFalse(needsDefaultInterfaceMethodDesugaring());
testForRuntime(parameters)
.addInnerClasses(InvokeSuperToEmulatedDefaultMethodTest.class)
@@ -51,15 +67,10 @@
}
@Test
- public void testDesugaring() throws Exception {
+ public void testDesugaring() throws Throwable {
assumeTrue(needsDefaultInterfaceMethodDesugaring());
-
- testForD8()
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
- .addInnerClasses(InvokeSuperToEmulatedDefaultMethodTest.class)
- .setMinApi(parameters.getApiLevel())
- .enableLibraryDesugaring(parameters.getApiLevel())
- .compile()
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED);
}
diff --git a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
index 342f9a4..eb211e6 100644
--- a/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/InvokeSuperToRewrittenDefaultMethodTest.java
@@ -3,35 +3,50 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.desugar;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
-import com.android.tools.r8.TestDiagnosticMessages;
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;
+import com.google.common.collect.ImmutableList;
import java.util.List;
import java.util.function.Consumer;
import java.util.function.IntConsumer;
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 InvokeSuperToRewrittenDefaultMethodTest extends DesugaredLibraryTestBase {
private static final String EXPECTED = StringUtils.lines("Y", "89");
- @Parameterized.Parameters(name = "{0}")
+ private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
- return buildParameters(getTestParameters().withAllRuntimesAndApiLevels().build());
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ getJdk8Jdk11(),
+ ImmutableList.of(D8_L8DEBUG));
}
- private final TestParameters parameters;
-
- public InvokeSuperToRewrittenDefaultMethodTest(TestParameters parameters) {
+ public InvokeSuperToRewrittenDefaultMethodTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
private boolean needsDefaultInterfaceMethodDesugaring() {
@@ -41,6 +56,7 @@
@Test
public void testReference() throws Exception {
+ assumeFalse("Run only once.", libraryDesugaringSpecification == JDK11);
assumeFalse(needsDefaultInterfaceMethodDesugaring());
testForRuntime(parameters)
.addInnerClasses(InvokeSuperToRewrittenDefaultMethodTest.class)
@@ -49,19 +65,15 @@
}
@Test
- public void testDesugaring() throws Exception {
+ public void testDesugaring() throws Throwable {
assumeTrue(needsDefaultInterfaceMethodDesugaring());
- testForD8()
- .addInnerClasses(InvokeSuperToRewrittenDefaultMethodTest.class)
- .setMinApi(parameters.getApiLevel())
- .addLibraryFiles(getLibraryFile())
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages)
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED);
}
+
public interface CharConsumer extends Consumer<Character>, IntConsumer {
void accept(char c);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BackwardsCompatibleSpecificationTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BackwardsCompatibleSpecificationTest.java
index 817268d..9fe7609 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BackwardsCompatibleSpecificationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BackwardsCompatibleSpecificationTest.java
@@ -3,16 +3,18 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.desugar.desugaredlibrary;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.ArrayList;
import java.util.List;
-import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -24,15 +26,19 @@
@Parameterized.Parameters(name = "{1}")
public static List<Object[]> data() {
- return buildParameters(getTestParameters().withNoneRuntime().build(), RELEASES);
+ return buildParameters(
+ getTestParameters().withNoneRuntime().build(), ImmutableList.of(JDK8), RELEASES);
}
- private final Path desugaredLib = ToolHelper.getDesugarJDKLibs();
- private final Path desugaredSpec = ToolHelper.getDesugarLibJsonForTesting();
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
private final String release;
- public BackwardsCompatibleSpecificationTest(TestParameters parameters, String release) {
+ public BackwardsCompatibleSpecificationTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ String release) {
parameters.assertNoneRuntime();
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
this.release = release;
}
@@ -42,16 +48,14 @@
@Test
public void test() throws Exception {
- Assume.assumeFalse(
- "When using JDK11 desugared library, we're not backward compatible to 2.0.74.",
- isJDK11DesugaredLibrary());
- ProcessResult result =
- ToolHelper.runJava(
- getReleaseJar(),
- "com.android.tools.r8.L8",
- "--desugared-lib",
- desugaredSpec.toString(),
- desugaredLib.toString());
+ ArrayList<String> command = new ArrayList<>();
+ command.add("com.android.tools.r8.L8");
+ command.add("--desugared-lib");
+ command.add(libraryDesugaringSpecification.getSpecification().toString());
+ for (Path desugarJdkLib : libraryDesugaringSpecification.getDesugarJdkLibs()) {
+ command.add(desugarJdkLib.toString());
+ }
+ ProcessResult result = ToolHelper.runJava(getReleaseJar(), command.toArray(new String[0]));
assertEquals(result.toString(), 0, result.exitCode);
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
index 38845cc..716e073 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
@@ -9,17 +9,12 @@
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
-import com.android.tools.r8.D8TestBuilder;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
-import com.android.tools.r8.StringResource;
-import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
@@ -65,41 +60,10 @@
}
@Test
- public void testInvalidLibrary() {
- Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
- // This is handwritten since this is really a special case: library desugaring with an
- // invalid library file passed.
- D8TestBuilder testBuilder =
- testForD8()
- .setMinApi(parameters.getApiLevel())
- .addProgramClasses(GuineaPig.class)
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.L))
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.builder()
- .setMinApi(parameters.getApiLevel())
- .addDesugaredLibraryConfiguration(
- StringResource.fromFile(libraryDesugaringSpecification.getSpecification()))
- .dontAddRunClasspath()
- .build());
- try {
- testBuilder.compile();
- } catch (Throwable t) {
- // Expected since we are compiling with an invalid set-up.
- }
- TestDiagnosticMessages diagnosticMessages = testBuilder.getState().getDiagnosticsMessages();
- assertTrue(
- diagnosticMessages
- .getWarnings()
- .get(0)
- .getDiagnosticMessage()
- .contains(
- "Desugared library requires to be compiled with a library file of API greater or"
- + " equal to"));
- }
-
- @Test
public void testDesugaredLibraryContent() throws Exception {
- Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
+ Assume.assumeTrue(
+ requiresAnyCoreLibDesugaring(
+ parameters.getApiLevel(), libraryDesugaringSpecification != JDK8));
testForL8(parameters.getApiLevel())
.apply(libraryDesugaringSpecification::configureL8TestBuilder)
.compile()
@@ -108,7 +72,9 @@
@Test
public void testDesugaredLibraryContentWithCoreLambdaStubsAsProgram() throws Exception {
- Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
+ Assume.assumeTrue(
+ requiresAnyCoreLibDesugaring(
+ parameters.getApiLevel(), libraryDesugaringSpecification != JDK8));
ArrayList<Path> coreLambdaStubs = new ArrayList<>();
coreLambdaStubs.add(ToolHelper.getCoreLambdaStubs());
testForL8(parameters.getApiLevel())
@@ -120,7 +86,9 @@
@Test
public void testDesugaredLibraryContentWithCoreLambdaStubsAsLibrary() throws Exception {
- Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
+ Assume.assumeTrue(
+ requiresAnyCoreLibDesugaring(
+ parameters.getApiLevel(), libraryDesugaringSpecification != JDK8));
testForL8(parameters.getApiLevel())
.apply(libraryDesugaringSpecification::configureL8TestBuilder)
.addLibraryFiles(ToolHelper.getCoreLambdaStubs())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
index 46743c8..4a9b0a0 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryDumpInputsTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.desugar.desugaredlibrary;
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertEquals;
@@ -53,7 +54,9 @@
@Test
public void testDumpToDirectory() throws Exception {
- Assume.assumeTrue(requiresAnyCoreLibDesugaring(parameters));
+ Assume.assumeTrue(
+ requiresAnyCoreLibDesugaring(
+ parameters.getApiLevel(), libraryDesugaringSpecification != JDK8));
Path dumpDir = temp.newFolder().toPath();
testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
.addProgramClasses(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryInvalidTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryInvalidTest.java
new file mode 100644
index 0000000..1834ea4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryInvalidTest.java
@@ -0,0 +1,96 @@
+// 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;
+
+import static com.android.tools.r8.ToolHelper.DESUGARED_JDK_8_LIB_JAR;
+import static com.android.tools.r8.ToolHelper.UNDESUGARED_JDK_11_LIB_JAR;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertFalse;
+
+import com.android.tools.r8.TestDiagnosticMessages;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.DesugaredLibraryTestBuilder;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.util.List;
+import org.junit.Assume;
+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 DesugaredLibraryInvalidTest extends DesugaredLibraryTestBase {
+
+ private final TestParameters parameters;
+ private final CompilationSpecification compilationSpecification;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ LibraryDesugaringSpecification jdk8InvalidLib =
+ new LibraryDesugaringSpecification(
+ "JDK8_INVALID_LIB",
+ DESUGARED_JDK_8_LIB_JAR,
+ "desugar_jdk_libs.json",
+ AndroidApiLevel.L);
+ LibraryDesugaringSpecification jdk11InvalidLib =
+ new LibraryDesugaringSpecification(
+ "JDK11_INVALID_LIB",
+ UNDESUGARED_JDK_11_LIB_JAR,
+ "jdk11/desugar_jdk_libs.json",
+ AndroidApiLevel.L);
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+ ImmutableList.of(jdk8InvalidLib, jdk11InvalidLib),
+ ImmutableList.of(D8_L8DEBUG));
+ }
+
+ public DesugaredLibraryInvalidTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
+ this.parameters = parameters;
+ this.compilationSpecification = compilationSpecification;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ }
+
+ @Test
+ public void testInvalidLibrary() throws IOException {
+ Assume.assumeTrue(
+ requiresAnyCoreLibDesugaring(
+ parameters.getApiLevel(), !libraryDesugaringSpecification.toString().contains("JDK8")));
+ DesugaredLibraryTestBuilder<?> testBuilder =
+ testForDesugaredLibrary(
+ parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addProgramClasses(GuineaPig.class);
+ try {
+ testBuilder.compile();
+ } catch (Throwable t) {
+ // Expected since we are compiling with an invalid set-up.
+ }
+ testBuilder.applyOnBuilder(
+ b -> {
+ TestDiagnosticMessages diagnosticsMessages = b.getState().getDiagnosticsMessages();
+ assertFalse(diagnosticsMessages.getWarnings().isEmpty());
+ assertTrue(
+ diagnosticsMessages
+ .getWarnings()
+ .get(0)
+ .getDiagnosticMessage()
+ .contains(
+ "Desugared library requires to be compiled with a library file of API greater"
+ + " or equal to"));
+ });
+ }
+
+ static class GuineaPig {
+ public static void main(String[] args) {}
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
index 6024ccb..b833d04 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryTestBase.java
@@ -4,19 +4,11 @@
package com.android.tools.r8.desugar.desugaredlibrary;
-import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
import static junit.framework.TestCase.assertEquals;
-import static junit.framework.TestCase.assertTrue;
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.DiagnosticsHandler;
-import com.android.tools.r8.L8Command;
import com.android.tools.r8.L8TestBuilder;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
-import com.android.tools.r8.OutputMode;
import com.android.tools.r8.StringConsumer;
-import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -27,28 +19,11 @@
import com.android.tools.r8.desugar.desugaredlibrary.test.DesugaredLibraryTestBuilder;
import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
-import com.android.tools.r8.tracereferences.TraceReferences;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.FileUtils;
-import com.android.tools.r8.utils.InternalOptions;
-import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
-import java.util.function.Consumer;
import org.junit.BeforeClass;
-import org.objectweb.asm.ClassReader;
-import org.objectweb.asm.ClassVisitor;
-import org.objectweb.asm.MethodVisitor;
public class DesugaredLibraryTestBase extends TestBase {
@@ -70,11 +45,6 @@
return property.contains("jdk11");
}
- public void setDesugaredLibrarySpecificationForTesting(
- InternalOptions options, DesugaredLibrarySpecification specification) {
- options.setDesugaredLibrarySpecification(specification);
- }
-
// For conversions tests, we need DexRuntimes where classes to convert are present (DexRuntimes
// above N and O depending if Stream or Time APIs are used), but we need to compile the program
// with a minAPI below to force the use of conversions.
@@ -122,7 +92,7 @@
protected boolean requiresAnyCoreLibDesugaring(AndroidApiLevel apiLevel, boolean isJDK11) {
return apiLevel.getLevel()
- <= (isJDK11 ? AndroidApiLevel.Sv2.getLevel() : AndroidApiLevel.N_MR1.getLevel());
+ <= (isJDK11 ? AndroidApiLevel.R.getLevel() : AndroidApiLevel.N_MR1.getLevel());
}
protected boolean requiresAnyCoreLibDesugaring(AndroidApiLevel apiLevel) {
@@ -145,79 +115,6 @@
return L8TestBuilder.create(apiLevel, backend, new TestState(temp));
}
- protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel) {
- return buildDesugaredLibrary(apiLevel, null, false);
- }
-
- protected Path buildDesugaredLibrary(
- AndroidApiLevel apiLevel, Consumer<InternalOptions> optionsModifier) {
- return buildDesugaredLibrary(apiLevel, null, false, ImmutableList.of(), optionsModifier);
- }
-
- protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel, String keepRules) {
- return buildDesugaredLibrary(apiLevel, keepRules, true);
- }
-
- protected Path buildDesugaredLibrary(AndroidApiLevel apiLevel, String keepRules, boolean shrink) {
- return buildDesugaredLibrary(apiLevel, keepRules, shrink, ImmutableList.of(), options -> {});
- }
-
- protected Path buildDesugaredLibrary(
- AndroidApiLevel apiLevel,
- String keepRules,
- boolean shrink,
- List<Path> additionalProgramFiles) {
- return buildDesugaredLibrary(
- apiLevel, keepRules, shrink, additionalProgramFiles, options -> {});
- }
-
- protected Path buildDesugaredLibrary(
- AndroidApiLevel apiLevel,
- String generatedKeepRules,
- boolean release,
- List<Path> additionalProgramFiles,
- Consumer<InternalOptions> optionsModifier) {
- try {
- return testForL8(apiLevel)
- .addProgramFiles(additionalProgramFiles)
- .addLibraryFiles(getLibraryFile())
- .applyIf(
- release,
- builder -> {
- if (generatedKeepRules != null && !generatedKeepRules.trim().isEmpty()) {
- builder.addGeneratedKeepRules(generatedKeepRules);
- }
- },
- L8TestBuilder::setDebug)
- .addOptionsModifier(optionsModifier)
- .setDesugarJDKLibsCustomConversions(ToolHelper.DESUGAR_LIB_CONVERSIONS)
- // If we compile extended library here, it means we use TestNG. TestNG requires
- // annotations, hence we disable annotation removal. This implies that extra warnings are
- // generated.
- .setDisableL8AnnotationRemoval(!additionalProgramFiles.isEmpty())
- .compile()
- .applyIf(
- additionalProgramFiles.isEmpty(),
- builder ->
- builder.inspectDiagnosticMessages(
- diagnostics ->
- assertTrue(
- // TODO(b/193597730): Fix JDK11 desugared library message,
- isJDK11DesugaredLibrary()
- || diagnostics.getInfos().stream()
- .noneMatch(
- string ->
- string
- .getDiagnosticMessage()
- .startsWith(
- "Invalid parameter counts in MethodParameter"
- + " attributes.")))))
- .writeToZip();
- } catch (CompilationFailedException | ExecutionException | IOException e) {
- throw new RuntimeException(e);
- }
- }
-
protected void assertLines2By2Correct(String stdOut) {
String[] lines = stdOut.split("\n");
assert lines.length % 2 == 0;
@@ -236,128 +133,6 @@
.toArray(Path[]::new);
}
- protected KeepRuleConsumer createKeepRuleConsumer(TestParameters parameters) {
- return LibraryDesugaringTestConfiguration.createKeepRuleConsumer(parameters);
- }
-
- public Path getDesugaredLibraryInCF(
- TestParameters parameters, Consumer<InternalOptions> configurationForLibraryCompilation)
- throws IOException, CompilationFailedException {
- Path desugaredLib = temp.newFolder().toPath().resolve("desugar_jdk_libs.jar");
- L8Command.Builder l8Builder =
- L8Command.builder()
- .addLibraryFiles(getLibraryFile())
- .addProgramFiles(ToolHelper.getDesugarJDKLibs())
- .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
- .setMode(CompilationMode.DEBUG)
- .addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
- .setMinApiLevel(parameters.getApiLevel().getLevel())
- .setOutput(desugaredLib, OutputMode.ClassFile);
-
- ToolHelper.runL8(l8Builder.build(), configurationForLibraryCompilation);
- return desugaredLib;
- }
-
- protected DesugaredLibrarySpecification configurationWithSupportAllCallbacksFromLibrary(
- InternalOptions options,
- boolean libraryCompilation,
- TestParameters parameters,
- boolean supportAllCallbacksFromLibrary) {
- return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecificationforTesting(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()),
- options.dexItemFactory(),
- options.reporter,
- libraryCompilation,
- parameters.getApiLevel().getLevel(),
- builder -> builder.setSupportAllCallbacksFromLibrary(supportAllCallbacksFromLibrary));
- }
-
- private Map<AndroidApiLevel, Path> desugaredLibraryClassFileCache = new HashMap<>();
-
- // Build the desugared library in class file format.
- public Path buildDesugaredLibraryClassFile(AndroidApiLevel apiLevel) throws Exception {
- Path desugaredLib = desugaredLibraryClassFileCache.get(apiLevel);
- if (desugaredLib != null) {
- return desugaredLib;
- }
- desugaredLib = temp.newFolder().toPath().resolve("desugar_jdk_libs.jar");
- L8Command.Builder l8Builder =
- L8Command.builder()
- .addLibraryFiles(getLibraryFile())
- .addProgramFiles(ToolHelper.getDesugarJDKLibs())
- .addProgramFiles(ToolHelper.DESUGAR_LIB_CONVERSIONS)
- .setMode(CompilationMode.DEBUG)
- .addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
- .setMinApiLevel(apiLevel.getLevel())
- .setOutput(desugaredLib, OutputMode.ClassFile);
- ToolHelper.runL8(l8Builder.build());
- desugaredLibraryClassFileCache.put(apiLevel, desugaredLib);
- return desugaredLib;
- }
-
- public String collectKeepRulesWithTraceReferences(
- Path desugaredProgramClassFile, Path desugaredLibraryClassFile) throws Exception {
- Path generatedKeepRules = temp.newFile().toPath();
- TraceReferences.run(
- "--keep-rules",
- "--lib",
- getLibraryFile().toString(),
- "--target",
- desugaredLibraryClassFile.toString(),
- "--source",
- desugaredProgramClassFile.toString(),
- "--output",
- generatedKeepRules.toString(),
- "--map-diagnostics",
- "error",
- "info");
- return FileUtils.readTextFile(generatedKeepRules, Charsets.UTF_8);
- }
-
- protected static ClassFileInfo extractClassFileInfo(byte[] classFileBytes) {
- class ClassFileInfoExtractor extends ClassVisitor {
- private String classBinaryName;
- private List<String> interfaces = new ArrayList<>();
- private final List<String> methodNames = new ArrayList<>();
-
- private ClassFileInfoExtractor() {
- super(ASM_VERSION);
- }
-
- @Override
- public void visit(
- int version,
- int access,
- String name,
- String signature,
- String superName,
- String[] interfaces) {
- classBinaryName = name;
- this.interfaces.addAll(Arrays.asList(interfaces));
- super.visit(version, access, name, signature, superName, interfaces);
- }
-
- @Override
- public MethodVisitor visitMethod(
- int access, String name, String desc, String signature, String[] exceptions) {
- methodNames.add(name);
- return super.visitMethod(access, name, desc, signature, exceptions);
- }
-
- ClassFileInfo getClassFileInfo() {
- return new ClassFileInfo(classBinaryName, interfaces, methodNames);
- }
- }
-
- ClassReader reader = new ClassReader(classFileBytes);
- ClassFileInfoExtractor extractor = new ClassFileInfoExtractor();
- reader.accept(
- extractor, ClassReader.SKIP_CODE | ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
- return extractor.getClassFileInfo();
- }
-
public interface KeepRuleConsumer extends StringConsumer {
String get();
@@ -377,28 +152,4 @@
};
}
}
-
- protected static class ClassFileInfo {
- private final String classBinaryName;
- private List<String> interfaces;
- private final List<String> methodNames;
-
- ClassFileInfo(String classBinaryNamename, List<String> interfaces, List<String> methodNames) {
- this.classBinaryName = classBinaryNamename;
- this.interfaces = interfaces;
- this.methodNames = methodNames;
- }
-
- public String getClassBinaryName() {
- return classBinaryName;
- }
-
- public List<String> getInterfaces() {
- return interfaces;
- }
-
- public List<String> getMethodNames() {
- return methodNames;
- }
- }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
index 2e09671..f744809 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/EmptyDesugaredLibrary.java
@@ -75,10 +75,7 @@
}
private boolean expectsEmptyDesugaredLibrary(AndroidApiLevel apiLevel) {
- if (libraryDesugaringSpecification != JDK8) {
- return apiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.S);
- }
- return !requiresAnyCoreLibDesugaring(apiLevel);
+ return !requiresAnyCoreLibDesugaring(apiLevel, libraryDesugaringSpecification != JDK8);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
index f0be12b..b6be183 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ExtractWrapperTypesTest.java
@@ -98,7 +98,7 @@
private final LibraryDesugaringSpecification libraryDesugaringSpecification;
- @Parameters(name = "{0}, spec: {1}, {2}")
+ @Parameters(name = "{0}, spec: {1}")
public static List<Object[]> data() {
return buildParameters(getTestParameters().withNoneRuntime().build(), getJdk8Jdk11());
}
@@ -147,7 +147,9 @@
minApi.getLevel());
MachineDesugaredLibrarySpecification specification =
spec.toMachineSpecification(
- new InternalOptions(factory, new Reporter()), getLibraryFile(), Timing.empty());
+ new InternalOptions(factory, new Reporter()),
+ libraryDesugaringSpecification.getLibraryFiles(),
+ Timing.empty());
Set<String> wrappersInSpec =
specification.getWrappers().keySet().stream()
.map(DexType::toString)
@@ -288,10 +290,10 @@
private CodeInspector getDesugaredApiJar() throws Exception {
Path out = temp.newFolder().toPath();
GenerateLintFiles desugaredApi =
- new GenerateLintFiles(
- ToolHelper.getDesugarLibJsonForTesting().toString(),
- ToolHelper.getDesugarJDKLibs().toString(),
- out.toString());
+ GenerateLintFiles.createForTesting(
+ libraryDesugaringSpecification.getSpecification(),
+ libraryDesugaringSpecification.getDesugarJdkLibs(),
+ out);
desugaredApi.run(targetApi.getLevel());
return new CodeInspector(
out.resolve("compile_api_level_" + targetApi.getLevel())
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java
index 397a46f..d22793d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/InvalidLibraryTest.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
-import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static org.hamcrest.core.StringContains.containsString;
@@ -83,8 +82,8 @@
@Test
public void testClasspathSupertype() throws Exception {
Assume.assumeTrue(
- requiresAnyCoreLibDesugaring(
- parameters.getApiLevel(), libraryDesugaringSpecification != JDK8));
+ "Date is present in the library above O",
+ parameters.getApiLevel().isLessThan(AndroidApiLevel.O));
testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
.addProgramClasses(Executor.class, LocalClass.class, LocalClassOverride.class)
.addClasspathClasses(SuperLibraryClass.class)
@@ -104,8 +103,8 @@
@Test
public void testNullSupertype() throws Exception {
Assume.assumeTrue(
- requiresAnyCoreLibDesugaring(
- parameters.getApiLevel(), libraryDesugaringSpecification != JDK8));
+ "Date is present in the library above O",
+ parameters.getApiLevel().isLessThan(AndroidApiLevel.O));
testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
.addProgramClasses(Executor.class, LocalClass.class, LocalClassOverride.class)
.setCustomLibrarySpecification(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
index eddeb8e..4b7a485 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
@@ -4,23 +4,23 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
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 com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.ThrowingSupplier;
import com.android.tools.r8.utils.codeinspector.CheckCastInstructionSubject;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -31,7 +31,6 @@
import com.android.tools.r8.utils.codeinspector.TryCatchSubject;
import com.android.tools.r8.utils.codeinspector.TypeSubject;
import com.google.common.collect.ImmutableSet;
-import java.nio.file.Path;
import java.time.DateTimeException;
import java.time.ZoneId;
import java.time.temporal.TemporalAccessor;
@@ -41,7 +40,6 @@
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
-import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -50,10 +48,7 @@
@RunWith(Parameterized.class)
public class JavaTimeTest extends DesugaredLibraryTestBase {
- private final TestParameters parameters;
- private final boolean shrinkDesugaredLibrary;
- private final boolean traceReferencesKeepRules;
- private static final String expectedOutput =
+ private static final String EXPECTED_OUTPUT =
StringUtils.lines(
"Caught java.time.format.DateTimeParseException",
"true",
@@ -64,31 +59,38 @@
"true",
"Hello, world");
- @Parameters(name = "{2}, shrinkDesugaredLibrary: {0}, traceReferencesKeepRules {1}")
+ private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
return buildParameters(
- BooleanUtils.values(),
- BooleanUtils.values(),
- getTestParameters()
- .withAllRuntimes()
- .withAllApiLevelsAlsoForCf()
- .withApiLevel(AndroidApiLevel.N)
- .build());
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+ getJdk8Jdk11(),
+ SPECIFICATIONS_WITH_CF2CF);
}
public JavaTimeTest(
- boolean shrinkDesugaredLibrary, boolean traceReferencesKeepRules, TestParameters parameters) {
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
- this.traceReferencesKeepRules = traceReferencesKeepRules;
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
- private void checkRewrittenInvokesForD8(CodeInspector inspector) {
- checkRewrittenInvokes(inspector, false);
- }
-
- private void checkRewrittenInvokesForR8(CodeInspector inspector) {
- checkRewrittenInvokes(inspector, true);
+ @Test
+ public void testTime() throws Throwable {
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .enableNoVerticalClassMergingAnnotations()
+ .enableInliningAnnotations()
+ .compile()
+ .inspect(i -> checkRewrittenInvokes(i, compilationSpecification.isProgramShrink()))
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
}
private void checkRewrittenInvokes(CodeInspector inspector, boolean isR8) {
@@ -96,7 +98,7 @@
Set<String> expectedCatchGuards;
Set<String> expectedCheckCastType;
String expectedInstanceOfTypes;
- if (!requiresTimeDesugaring(parameters)) {
+ if (!requiresTimeDesugaring(parameters, libraryDesugaringSpecification != JDK8)) {
expectedInvokeHolders =
SetUtils.newHashSet("java.time.Clock", "java.time.LocalDate", "java.time.ZoneId");
if (!isR8) {
@@ -149,7 +151,7 @@
.isGreaterThanOrEqualTo(TestBase.apiLevelWithDefaultInterfaceMethodsSupport())
&& isR8) {
String holder =
- requiresTimeDesugaring(parameters)
+ requiresTimeDesugaring(parameters, libraryDesugaringSpecification != JDK8)
? "j$.time.temporal.TemporalAccessor"
: "java.time.temporal.TemporalAccessor";
assertThat(
@@ -186,117 +188,6 @@
}
}
- private String desugaredLibraryKeepRules(
- KeepRuleConsumer keepRuleConsumer, ThrowingSupplier<Path, Exception> programSupplier)
- throws Exception {
- String desugaredLibraryKeepRules = null;
- if (shrinkDesugaredLibrary) {
- desugaredLibraryKeepRules = keepRuleConsumer.get();
- if (desugaredLibraryKeepRules != null) {
- if (traceReferencesKeepRules) {
- desugaredLibraryKeepRules =
- collectKeepRulesWithTraceReferences(
- programSupplier.get(), buildDesugaredLibraryClassFile(parameters.getApiLevel()));
- }
- }
- }
- return desugaredLibraryKeepRules;
- }
-
- @Test
- public void testTimeD8Cf() throws Exception {
- Assume.assumeTrue(shrinkDesugaredLibrary || !traceReferencesKeepRules);
-
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- // Use D8 to desugar with Java classfile output.
- Path jar =
- testForD8(Backend.CF)
- .addInnerClasses(JavaTimeTest.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .inspect(this::checkRewrittenInvokesForD8)
- .writeToZip();
-
- String desugaredLibraryKeepRules;
- if (shrinkDesugaredLibrary && !traceReferencesKeepRules && keepRuleConsumer.get() != null) {
- // Collection keep rules is only implemented in the DEX writer.
- assertEquals(0, keepRuleConsumer.get().length());
- desugaredLibraryKeepRules = "-keep class * { *; }";
- } else {
- desugaredLibraryKeepRules = desugaredLibraryKeepRules(keepRuleConsumer, () -> jar);
- }
-
- // Determine desugared library keep rules.
- if (parameters.getRuntime().isDex()) {
- // Convert to DEX without desugaring and run.
- testForD8()
- .addProgramFiles(jar)
- .setMinApi(parameters.getApiLevel())
- .disableDesugaring()
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- desugaredLibraryKeepRules,
- shrinkDesugaredLibrary)
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(expectedOutput);
- } else {
- // Run on the JVM with desugared library on classpath.
- testForJvm()
- .addProgramFiles(jar)
- .addRunClasspathFiles(buildDesugaredLibraryClassFile(parameters.getApiLevel()))
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(expectedOutput);
- }
- }
-
- @Test
- public void testTimeD8() throws Exception {
- Assume.assumeTrue(parameters.getRuntime().isDex());
- Assume.assumeTrue(shrinkDesugaredLibrary || !traceReferencesKeepRules);
-
- testForD8()
- .addInnerClasses(JavaTimeTest.class)
- .setMinApi(parameters.getApiLevel())
- .addLibraryFiles(getLibraryFile())
- .enableLibraryDesugaring(
- LibraryDesugaringTestConfiguration.builder()
- .setMinApi(parameters.getApiLevel())
- .withKeepRuleConsumer()
- .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
- .build())
- .compile()
- .inspect(this::checkRewrittenInvokesForD8)
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(expectedOutput);
- }
-
- @Test
- public void testTimeR8() throws Exception {
- Assume.assumeTrue(parameters.getRuntime().isDex());
- Assume.assumeTrue(shrinkDesugaredLibrary || !traceReferencesKeepRules);
-
- testForR8(parameters.getBackend())
- .addInnerClasses(JavaTimeTest.class)
- .addKeepMainRule(TestClass.class)
- .enableNoVerticalClassMergingAnnotations()
- .setMinApi(parameters.getApiLevel())
- .addLibraryFiles(getLibraryFile())
- .enableLibraryDesugaring(
- LibraryDesugaringTestConfiguration.builder()
- .setMinApi(parameters.getApiLevel())
- .withKeepRuleConsumer()
- .setMode(shrinkDesugaredLibrary ? CompilationMode.RELEASE : CompilationMode.DEBUG)
- .build())
- .enableInliningAnnotations()
- .compile()
- .inspect(this::checkRewrittenInvokesForR8)
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(expectedOutput);
- }
-
@NoVerticalClassMerging
static class TemporalAccessorImpl implements TemporalAccessor {
@Override
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilFunctionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilFunctionTest.java
index b8fd76f..d14b845 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilFunctionTest.java
@@ -4,6 +4,12 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8SHRINK_TR;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.R8_L8SHRINK;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.R8_L8SHRINK_TR;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
@@ -11,10 +17,12 @@
import com.android.tools.r8.KeepConstantArguments;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+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 com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableSet;
import java.util.List;
import java.util.function.Function;
import org.junit.Test;
@@ -25,19 +33,27 @@
@RunWith(Parameterized.class)
public class JavaUtilFunctionTest extends DesugaredLibraryTestBase {
- private final TestParameters parameters;
- private final boolean shrinkDesugaredLibrary;
- private static final String expectedOutput = StringUtils.lines("Hello, world", "Hello, world");
+ private static final String EXPECTED_OUTPUT = StringUtils.lines("Hello, world", "Hello, world");
- @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
return buildParameters(
- BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+ getJdk8Jdk11(),
+ ImmutableSet.of(D8_L8DEBUG, D8_L8SHRINK, R8_L8SHRINK, D8_L8SHRINK_TR, R8_L8SHRINK_TR));
}
- public JavaUtilFunctionTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ public JavaUtilFunctionTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
private void checkRewrittenArguments(CodeInspector inspector) {
@@ -59,46 +75,17 @@
}
@Test
- public void testJavaUtilFunctionD8() throws Exception {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForD8()
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(JavaUtilFunctionTest.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .setIncludeClassesChecksum(true)
- .compile()
- .inspect(this::checkRewrittenArguments)
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(expectedOutput);
- }
-
- @Test
- public void testJavaUtilFunctionR8() throws Exception {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForR8(parameters.getBackend())
- .addLibraryFiles(getLibraryFile())
+ public void testJavaUtilFunction() throws Throwable {
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
.noMinification()
- .addKeepMainRule(TestClass.class)
- .addInnerClasses(JavaUtilFunctionTest.class)
- .setMinApi(parameters.getApiLevel())
.enableConstantArgumentAnnotations()
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
.inspect(this::checkRewrittenArguments)
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
.run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(expectedOutput);
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
}
static class TestClass {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilOptionalTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilOptionalTest.java
index e2271ae..7c98967 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilOptionalTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaUtilOptionalTest.java
@@ -4,22 +4,26 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
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.LibraryDesugaringTestConfiguration;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
+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 com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.InvokeInstructionSubject;
+import com.google.common.collect.ImmutableList;
import java.nio.file.Paths;
import java.util.Iterator;
+import java.util.List;
import java.util.Optional;
import java.util.OptionalDouble;
import java.util.OptionalInt;
@@ -27,19 +31,30 @@
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 JavaUtilOptionalTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ ImmutableList.of(D8_L8DEBUG));
}
- public JavaUtilOptionalTest(TestParameters parameters) {
+ public JavaUtilOptionalTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
private void checkRewrittenInvokes(CodeInspector inspector) {
@@ -63,7 +78,7 @@
}
@Test
- public void testJavaUtilOptional() throws Exception {
+ public void testJavaUtilOptional() throws Throwable {
String expectedOutput =
StringUtils.lines(
"false",
@@ -78,12 +93,8 @@
"false",
"true",
"42.42");
- testForD8()
- .addInnerClasses(JavaUtilOptionalTest.class)
- .addLibraryFiles(getLibraryFile())
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
.compile()
.inspect(this::checkRewrittenInvokes)
.run(parameters.getRuntime(), TestClass.class)
@@ -92,14 +103,9 @@
@Test
public void testJavaOptionalJava9() throws Exception {
- testForD8()
- .addLibraryFiles(getLibraryFile())
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
.addProgramFiles(
Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR).resolve("backport" + JAR_EXTENSION))
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compile()
.run(parameters.getRuntime(), "backport.OptionalBackportJava9Main")
.assertSuccess();
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LegacyDesugaredLibraryConfigurationParsingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LegacyDesugaredLibraryConfigurationParsingTest.java
index ffc072c..944036e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LegacyDesugaredLibraryConfigurationParsingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LegacyDesugaredLibraryConfigurationParsingTest.java
@@ -16,7 +16,7 @@
import com.android.tools.r8.TestDiagnosticMessagesImpl;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.desugaredlibrary.legacyspecification.LegacyDesugaredLibrarySpecification;
@@ -117,7 +117,9 @@
public void testReference() throws Exception {
// Just test that the reference file parses without issues.
LegacyDesugaredLibrarySpecification spec =
- runPassing(StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
+ runPassing(
+ StringResource.fromFile(
+ LibraryDesugaringSpecification.RELEASED_1_1_5.getSpecification()));
assertEquals(libraryCompilation, spec.isLibraryCompilation());
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibraryEmptySubclassInterfaceTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibraryEmptySubclassInterfaceTest.java
index 18989a3..0b048b4 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibraryEmptySubclassInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LibraryEmptySubclassInterfaceTest.java
@@ -4,11 +4,14 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+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.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import org.junit.Test;
@@ -20,66 +23,48 @@
public class LibraryEmptySubclassInterfaceTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
- private final boolean shrinkDesugaredLibrary;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ @Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
return buildParameters(
- BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ DEFAULT_SPECIFICATIONS);
}
public LibraryEmptySubclassInterfaceTest(
- boolean shrinkDesugaredLibrary, TestParameters parameters) {
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
- public void testD8() throws Exception {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForD8()
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(LibraryEmptySubclassInterfaceTest.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ public void testEmptySubclassInterface() throws Throwable {
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Executor.class)
+ .noMinification()
.compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
+ .inspectKeepRules(this::assertExpectedKeepRules)
.run(parameters.getRuntime(), Executor.class)
.assertSuccessWithOutputLines(getResult());
- assertExpectedKeepRules(keepRuleConsumer);
}
- private void assertExpectedKeepRules(KeepRuleConsumer keepRuleConsumer) {
+ private void assertExpectedKeepRules(List<String> keepRuleList) {
if (!requiresEmulatedInterfaceCoreLibDesugaring(parameters)) {
return;
}
- String keepRules = keepRuleConsumer.get();
- assertThat(keepRules, containsString("-keep class j$.util.concurrent.ConcurrentHashMap"));
- }
-
- @Test
- public void testR8() throws Exception {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForR8(Backend.DEX)
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(LibraryEmptySubclassInterfaceTest.class)
- .addKeepMainRule(Executor.class)
- .noMinification()
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
- .run(parameters.getRuntime(), Executor.class)
- .assertSuccessWithOutputLines(getResult());
- assertExpectedKeepRules(keepRuleConsumer);
+ StringBuilder keepRules = new StringBuilder();
+ for (String kr : keepRuleList) {
+ keepRules.append("\n").append(kr);
+ }
+ assertThat(
+ keepRules.toString(), containsString("-keep class j$.util.concurrent.ConcurrentHashMap"));
}
private String getResult() {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
index de87214..ebd2e9f 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LinkedHashSetTest.java
@@ -4,10 +4,15 @@
package com.android.tools.r8.desugar.desugaredlibrary;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.google.common.collect.ImmutableList;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
@@ -15,31 +20,38 @@
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 LinkedHashSetTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ ImmutableList.of(D8_L8DEBUG));
}
- public LinkedHashSetTest(TestParameters parameters) {
+ public LinkedHashSetTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
- public void testLinkedHashSetOverrides() throws Exception {
+ public void testLinkedHashSet() throws Throwable {
String stdOut =
- testForD8()
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(LinkedHashSetTest.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compile()
+ testForDesugaredLibrary(
+ parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
.run(parameters.getRuntime(), Executor.class)
.assertSuccess()
.getStdOut();
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
index cd54e5d..ddf8c9d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LintFilesTest.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -11,8 +13,8 @@
import com.android.tools.r8.GenerateLintFiles;
import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
@@ -33,13 +35,17 @@
@RunWith(Parameterized.class)
public class LintFilesTest extends DesugaredLibraryTestBase {
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withNoneRuntime().build();
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+ @Parameters(name = "{0}, spec: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(getTestParameters().withNoneRuntime().build(), getJdk8Jdk11());
}
- public LintFilesTest(TestParameters parameters) {
- parameters.assertNoneRuntime();
+ public LintFilesTest(
+ TestParameters parameters, LibraryDesugaringSpecification libraryDesugaringSpecification) {
+ assert parameters.isNoneRuntime();
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
}
private void checkFileContent(AndroidApiLevel minApiLevel, Path lintFile) throws Exception {
@@ -52,7 +58,8 @@
// ConcurrentHashMap is fully supported on JDK 11.
assertEquals(
- isJDK11DesugaredLibrary(), methods.contains("java/util/concurrent/ConcurrentHashMap"));
+ libraryDesugaringSpecification != JDK8,
+ methods.contains("java/util/concurrent/ConcurrentHashMap"));
// No parallel* methods pre L, and all stream methods supported from L.
assertEquals(
@@ -79,7 +86,7 @@
methods.contains(
"java/util/stream/IntStream#allMatch(Ljava/util/function/IntPredicate;)Z"));
- if (isJDK11DesugaredLibrary()) {
+ if (libraryDesugaringSpecification != JDK8) {
// TODO(b/203382252): Investigate why the following assertions are not working on JDK 11.
return;
}
@@ -118,16 +125,20 @@
@Test
public void testFileContent() throws Exception {
Path directory = temp.newFolder().toPath();
+ Path jdkLibJar =
+ libraryDesugaringSpecification == JDK8
+ ? ToolHelper.DESUGARED_JDK_8_LIB_JAR
+ : ToolHelper.UNDESUGARED_JDK_11_LIB_JAR;
GenerateLintFiles.main(
new String[] {
- ToolHelper.getDesugarLibJsonForTesting().toString(),
- ToolHelper.getDesugarJDKLibs().toString(),
+ libraryDesugaringSpecification.getSpecification().toString(),
+ jdkLibJar.toString(),
directory.toString()
});
InternalOptions options = new InternalOptions(new DexItemFactory(), new Reporter());
DesugaredLibrarySpecification desugaredLibrarySpecification =
DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()),
+ StringResource.fromFile(libraryDesugaringSpecification.getSpecification()),
options.itemFactory,
options.reporter,
false,
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
index ccef7e8..51fc891 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11TestLibraryDesugaringSpecification.EXTENSION_PATH;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.CoreMatchers.containsString;
@@ -21,9 +22,9 @@
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11TestLibraryDesugaringSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.errors.DuplicateTypesDiagnostic;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -40,13 +41,17 @@
@RunWith(Parameterized.class)
public class MergingJ$Test extends DesugaredLibraryTestBase {
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withNoneRuntime().build();
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+ @Parameters(name = "{0}, spec: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(getTestParameters().withNoneRuntime().build(), getJdk8Jdk11());
}
- public MergingJ$Test(TestParameters parameters) {
- parameters.assertNoneRuntime();
+ public MergingJ$Test(
+ TestParameters parameters, LibraryDesugaringSpecification libraryDesugaringSpecification) {
+ assert parameters.isNoneRuntime();
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
}
@Test
@@ -58,7 +63,7 @@
() ->
testForD8()
.addProgramFiles(mergerInputPart1, mergerInputPart2)
- .addLibraryFiles(getLibraryFile())
+ .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
.compileWithExpectedDiagnostics(
diagnostics -> {
diagnostics
@@ -75,7 +80,7 @@
D8Command command =
D8Command.builder()
.addProgramFiles(mergerInputPart1, mergerInputPart2)
- .addLibraryFiles(getLibraryFile())
+ .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
.setOutput(merged, OutputMode.DexIndexed)
.build();
try {
@@ -109,10 +114,10 @@
Path outputDex = temp.newFolder().toPath().resolve("merger-input-dex.zip");
L8.run(
L8Command.builder()
- .addLibraryFiles(getLibraryFile())
- .addProgramFiles(ToolHelper.getDesugarJDKLibs())
+ .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
+ .addProgramFiles(libraryDesugaringSpecification.getDesugarJdkLibs())
.addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
+ StringResource.fromFile(libraryDesugaringSpecification.getSpecification()))
.setMinApiLevel(AndroidApiLevel.B.getLevel())
.setOutput(outputDex, OutputMode.DexIndexed)
.build());
@@ -127,11 +132,11 @@
Jdk11TestLibraryDesugaringSpecification.setUp();
L8.run(
L8Command.builder()
- .addLibraryFiles(getLibraryFile())
- .addLibraryFiles(ToolHelper.getDesugarJDKLibs())
+ .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
+ .addLibraryFiles(libraryDesugaringSpecification.getDesugarJdkLibs())
.addProgramFiles(EXTENSION_PATH)
.addDesugaredLibraryConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()))
+ StringResource.fromFile(libraryDesugaringSpecification.getSpecification()))
.setMinApiLevel(AndroidApiLevel.B.getLevel())
.setOutput(outputDex, OutputMode.DexIndexed)
.build());
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java
index 6ab6b2f..20e61c2 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MinimalInterfaceSuperTest.java
@@ -4,38 +4,53 @@
package com.android.tools.r8.desugar.desugaredlibrary;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+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.TestParametersCollection;
+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.util.AbstractCollection;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
+import java.util.List;
import java.util.function.Predicate;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
@SuppressWarnings("ALL")
@RunWith(Parameterized.class)
public class MinimalInterfaceSuperTest extends DesugaredLibraryTestBase {
- private final TestParameters parameters;
-
- @Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimes().withAllApiLevels().build();
- }
-
- public MinimalInterfaceSuperTest(TestParameters parameters) {
- this.parameters = parameters;
- }
-
private static final String EXPECTED_OUTPUT = StringUtils.lines("removeIf from Col1Itf");
+ private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ DEFAULT_SPECIFICATIONS);
+ }
+
+ public MinimalInterfaceSuperTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
+ this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
+ }
+
@Test
- public void testCustomCollectionR8() throws Exception {
+ public void testMinimalInterfaceSuper() throws Exception {
if (parameters.isCfRuntime()) {
testForJvm()
.addInnerClasses(MinimalInterfaceSuperTest.class)
@@ -43,15 +58,9 @@
.assertSuccessWithOutput(EXPECTED_OUTPUT);
return;
}
- testForR8(parameters.getBackend())
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(MinimalInterfaceSuperTest.class)
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
.addKeepMainRule(Main.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compile()
- .assertNoMessages()
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MonthTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MonthTest.java
index fbc2ad7..943c7a9 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MonthTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MonthTest.java
@@ -4,33 +4,49 @@
package com.android.tools.r8.desugar.desugaredlibrary;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
+
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime;
+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.time.Month;
import java.time.format.TextStyle;
+import java.util.List;
import java.util.Locale;
-import org.junit.Assume;
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 MonthTest extends DesugaredLibraryTestBase {
- private final TestParameters parameters;
private static final String EXPECTED_JAVA_8_OUTPUT = StringUtils.lines("4");
private static final String EXPECTED_JAVA_9_OUTPUT = StringUtils.lines("April");
- @Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+ private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ DEFAULT_SPECIFICATIONS);
}
- public MonthTest(TestParameters parameters) {
+ public MonthTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
private String getExpectedResult(TestParameters parameters) {
@@ -41,14 +57,14 @@
return EXPECTED_JAVA_8_OUTPUT;
}
assert parameters.isDexRuntime();
- if (requiresTimeDesugaring(parameters)) {
+ if (requiresTimeDesugaring(parameters, libraryDesugaringSpecification != JDK8)) {
return EXPECTED_JAVA_8_OUTPUT;
}
return EXPECTED_JAVA_9_OUTPUT;
}
@Test
- public void testMonthD8() throws Exception {
+ public void testMonth() throws Exception {
if (parameters.isCfRuntime()) {
testForJvm()
.addInnerClasses(MonthTest.class)
@@ -56,28 +72,9 @@
.assertSuccessWithOutput(getExpectedResult(parameters));
return;
}
- testForD8(parameters.getBackend())
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(MonthTest.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compile()
- .run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutput(getExpectedResult(parameters));
- }
-
- @Test
- public void testMonthR8() throws Exception {
- Assume.assumeTrue(parameters.isDexRuntime());
- testForR8(parameters.getBackend())
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(MonthTest.class)
- .addKeepMainRule(MonthTest.Main.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compile()
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutput(getExpectedResult(parameters));
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NeverMergeCoreLibDesugarClasses.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NeverMergeCoreLibDesugarClasses.java
index 607ff9b..82ca473 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NeverMergeCoreLibDesugarClasses.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NeverMergeCoreLibDesugarClasses.java
@@ -4,34 +4,50 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.smali.SmaliBuilder;
+import com.android.tools.r8.utils.AndroidApiLevel;
import com.google.common.collect.ImmutableList;
+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;
+import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class NeverMergeCoreLibDesugarClasses extends DesugaredLibraryTestBase {
private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection
- data() {
- return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ ImmutableList.of(D8_L8DEBUG));
}
- public NeverMergeCoreLibDesugarClasses(TestParameters parameters) {
+ public NeverMergeCoreLibDesugarClasses(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
@@ -44,7 +60,7 @@
testForD8()
.addInnerClasses(NeverMergeCoreLibDesugarClasses.class)
.addProgramDexFileData(builder.compile())
- .setMinApi(parameters.getRuntime())
+ .setMinApi(parameters.getApiLevel())
.compileWithExpectedDiagnostics(
diagnostics -> {
diagnostics.assertErrorsCount(1);
@@ -65,13 +81,20 @@
@Test
public void testDesugaredCoreLibrary() throws Exception {
- Assume.assumeTrue(parameters.getApiLevel().getLevel() < 26);
+ Assume.assumeTrue(parameters.getApiLevel().getLevel() < AndroidApiLevel.O.getLevel());
try {
+ Path input =
+ testForL8(parameters.getApiLevel())
+ .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
+ .setDebug()
+ .setDesugarJDKLibsCustomConversions(ToolHelper.DESUGAR_LIB_CONVERSIONS)
+ .compile()
+ .writeToZip();
testForD8()
.addInnerClasses(NeverMergeCoreLibDesugarClasses.class)
- .addLibraryFiles(getLibraryFile())
- .setMinApi(parameters.getRuntime())
- .addProgramFiles(buildDesugaredLibrary(parameters.getApiLevel()))
+ .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
+ .setMinApi(parameters.getApiLevel())
+ .addProgramFiles(input)
.compileWithExpectedDiagnostics(
diagnostics -> {
diagnostics.assertErrorsCount(1);
@@ -93,14 +116,9 @@
@Test
public void testTestCodeRuns() throws Exception {
// j$.util.Function is not present in recent APIs.
- Assume.assumeTrue(parameters.getApiLevel().getLevel() < 24);
- testForD8()
- .addInnerClasses(NeverMergeCoreLibDesugarClasses.class)
- .addLibraryFiles(getLibraryFile())
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compile()
+ Assume.assumeTrue(parameters.getApiLevel().getLevel() < AndroidApiLevel.N.getLevel());
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutputLines("Hello, world!");
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDefaultMethodOverrideInLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDefaultMethodOverrideInLibraryTest.java
index 87d0bbd..696d737 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDefaultMethodOverrideInLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDefaultMethodOverrideInLibraryTest.java
@@ -3,16 +3,19 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.desugar.desugaredlibrary;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.TestRuntime.CfVm;
+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 com.google.common.collect.ImmutableList;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.LinkedList;
@@ -21,6 +24,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
/**
* This test checks that if a default interface method in a library is not overridden by a class
@@ -37,14 +41,24 @@
static final String EXPECTED = StringUtils.lines("MyIntegerList::removeIf", "false", "false");
private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameterized.Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimes().withAllApiLevels().build();
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ ImmutableList.of(D8_L8DEBUG));
}
- public NoDefaultMethodOverrideInLibraryTest(TestParameters parameters) {
+ public NoDefaultMethodOverrideInLibraryTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
@@ -69,13 +83,8 @@
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutput(EXPECTED);
} else {
- testForD8()
- .addLibraryFiles(getLibraryFile())
- .setMinApi(parameters.getApiLevel())
- .addInnerClasses(NoDefaultMethodOverrideInLibraryTest.class)
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compile()
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutput(EXPECTED);
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDesugaredLibraryDexFileTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDesugaredLibraryDexFileTest.java
index 3c83b83..5ddc567 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDesugaredLibraryDexFileTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoDesugaredLibraryDexFileTest.java
@@ -4,10 +4,13 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+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.assertTrue;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.util.ArrayList;
import java.util.Collection;
@@ -16,6 +19,7 @@
import java.util.Iterator;
import java.util.List;
import java.util.SortedSet;
+import org.junit.Assert;
import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -26,50 +30,37 @@
public class NoDesugaredLibraryDexFileTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
- private final boolean shrinkDesugaredLibrary;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ @Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
return buildParameters(
- BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ DEFAULT_SPECIFICATIONS);
}
- public NoDesugaredLibraryDexFileTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ public NoDesugaredLibraryDexFileTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
- public void testCustomCollectionD8() throws Exception {
+ public void testNoDesugaredLibraryDexFile() throws Throwable {
Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForD8()
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(NoDesugaredLibraryDexFileTest.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .inspect(this::assertNoForwardingStreamMethod)
- .run(parameters.getRuntime(), Executor.class)
- .assertSuccessWithOutputLines("1", "0");
- assertTrue(keepRuleConsumer.get().isEmpty());
- }
-
- @Test
- public void testCustomCollectionR8() throws Exception {
- Assume.assumeTrue(requiresEmulatedInterfaceCoreLibDesugaring(parameters));
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForR8(parameters.getBackend())
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(NoDesugaredLibraryDexFileTest.class)
- .setMinApi(parameters.getApiLevel())
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
.addKeepClassAndMembersRules(Executor.class)
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
.inspect(this::assertNoForwardingStreamMethod)
+ .inspectKeepRules(Assert::assertNull)
.run(parameters.getRuntime(), Executor.class)
.assertSuccessWithOutputLines("1", "0");
- assertTrue(keepRuleConsumer.get().isEmpty());
}
private void assertNoForwardingStreamMethod(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoForwardingMethodsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoForwardingMethodsTest.java
index 298b653..c799716 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoForwardingMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/NoForwardingMethodsTest.java
@@ -4,10 +4,13 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+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.assertTrue;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.util.ArrayList;
import java.util.Collection;
@@ -26,54 +29,33 @@
public class NoForwardingMethodsTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
- private final boolean shrinkDesugaredLibrary;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ @Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
return buildParameters(
- BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ DEFAULT_SPECIFICATIONS);
}
- public NoForwardingMethodsTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ public NoForwardingMethodsTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
- public void testCustomCollectionD8() throws Exception {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForD8()
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(NoForwardingMethodsTest.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .inspect(this::assertNoForwardingStreamMethod)
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
- .run(parameters.getRuntime(), Executor.class)
- .assertSuccessWithOutputLines("str:1", "0");
- }
-
- @Test
- public void testCustomCollectionR8() throws Exception {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForR8(parameters.getBackend())
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(NoForwardingMethodsTest.class)
- .setMinApi(parameters.getApiLevel())
+ public void testNoForwardingMethods() throws Throwable {
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
.addKeepClassAndMembersRules(Executor.class)
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
.inspect(this::assertNoForwardingStreamMethod)
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
.run(parameters.getRuntime(), Executor.class)
.assertSuccessWithOutputLines("str:1", "0");
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
index e05e09a..f503773 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ObjectsTest.java
@@ -4,28 +4,27 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static com.android.tools.r8.ToolHelper.DESUGARED_JDK_8_LIB_JAR;
+import static com.android.tools.r8.ToolHelper.UNDESUGARED_JDK_11_LIB_JAR;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethod;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.onlyIf;
import static org.hamcrest.MatcherAssert.assertThat;
-import static org.junit.Assert.assertEquals;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.StringResource;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
-import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
-import com.android.tools.r8.utils.structural.Ordered;
import com.google.common.collect.ImmutableList;
-import java.nio.file.Path;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
@@ -63,43 +62,38 @@
"3",
"4");
- private final TestParameters parameters;
private final boolean libraryDesugarJavaUtilObjects;
- private final boolean shrinkDesugaredLibrary = false;
- private final Path androidJar;
- @Parameters(name = "{0}")
+ private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
+ LibraryDesugaringSpecification jdk8MaxCompileSdk =
+ new LibraryDesugaringSpecification(
+ "JDK8_MAX", DESUGARED_JDK_8_LIB_JAR, "desugar_jdk_libs.json", AndroidApiLevel.LATEST);
+ LibraryDesugaringSpecification jdk11MaxCompileSdk =
+ new LibraryDesugaringSpecification(
+ "JDK11_MAX",
+ UNDESUGARED_JDK_11_LIB_JAR,
+ "jdk11/desugar_jdk_libs.json",
+ AndroidApiLevel.LATEST);
return buildParameters(
- getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build(),
+ ImmutableList.of(JDK8, JDK11, jdk8MaxCompileSdk, jdk11MaxCompileSdk),
+ SPECIFICATIONS_WITH_CF2CF);
}
- public ObjectsTest(TestParameters parameters) {
+ public ObjectsTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
- this.libraryDesugarJavaUtilObjects = isJDK11DesugaredLibrary();
- this.androidJar =
- ToolHelper.getAndroidJar(
- Ordered.max(parameters.getApiLevel(), getRequiredCompilationAPILevel()));
- }
-
- DesugaredLibrarySpecification desugaredLibrarySpecification(
- InternalOptions options, boolean libraryCompilation, TestParameters parameters) {
- return DesugaredLibrarySpecificationParser.parseDesugaredLibrarySpecification(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()),
- options.dexItemFactory(),
- options.reporter,
- libraryCompilation,
- parameters.getApiLevel().getLevel());
- }
-
- private void configurationForProgramCompilation(InternalOptions options) {
- setDesugaredLibrarySpecificationForTesting(
- options, desugaredLibrarySpecification(options, false, parameters));
- }
-
- private void configurationForLibraryCompilation(InternalOptions options) {
- setDesugaredLibrarySpecificationForTesting(
- options, desugaredLibrarySpecification(options, true, parameters));
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
+ this.libraryDesugarJavaUtilObjects =
+ !libraryDesugaringSpecification.toString().contains("JDK8");
}
private Matcher<MethodSubject> invokesObjectsCompare(String holder) {
@@ -291,129 +285,20 @@
}
@Test
- public void testD8Cf() throws Exception {
- // Adjust API level if running on JDK 8. The java.util.Objects methods added in
- // Android R where added in JDK 9, so setting the the API level to Android P will backport
- // these methods for JDK 8.
- AndroidApiLevel apiLevel = parameters.getApiLevel();
- if (parameters.getRuntime().isCf()
- && parameters.getRuntime().asCf().getVm() == CfVm.JDK8
- && apiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.R)) {
- apiLevel = AndroidApiLevel.P;
- }
-
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- // Use D8 to desugar with Java classfile output.
- Path jar =
- testForD8(Backend.CF)
- .addLibraryFiles(androidJar)
- .addOptionsModification(this::configurationForProgramCompilation)
- .addInnerClasses(ObjectsTest.class)
- .addProgramClassFileData(dumpAndroidRUtilsObjectsMethods())
- .setMinApi(apiLevel)
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .inspect(this::inspect)
- .writeToZip();
-
- if (parameters.getRuntime().isDex()) {
- // Collection keep rules is only implemented in the DEX writer.
- String desugaredLibraryKeepRules = keepRuleConsumer.get();
- if (desugaredLibraryKeepRules != null) {
- assertEquals(0, desugaredLibraryKeepRules.length());
- desugaredLibraryKeepRules = "-keep class * { *; }";
- }
-
- // Convert to DEX without desugaring and run.
- testForD8()
- .addLibraryFiles(androidJar)
- .addProgramFiles(jar)
- .setMinApi(apiLevel)
- .disableDesugaring()
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- (apiLevel_, keepRules, shrink) ->
- buildDesugaredLibrary(
- apiLevel_,
- keepRules,
- shrink,
- ImmutableList.of(),
- this::configurationForLibraryCompilation),
- parameters.getApiLevel(),
- desugaredLibraryKeepRules,
- shrinkDesugaredLibrary)
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED_OUTPUT);
- } else {
- // Build the desugared library in class file format.
- Path desugaredLib =
- getDesugaredLibraryInCF(parameters, this::configurationForLibraryCompilation);
-
- // Run on the JVM with desugared library on classpath.
- testForJvm()
- .addProgramFiles(jar)
- .addRunClasspathFiles(desugaredLib)
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED_OUTPUT);
- }
- }
-
- @Test
- public void testD8() throws Exception {
- Assume.assumeTrue(parameters.getRuntime().isDex());
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForD8()
- .addLibraryFiles(androidJar)
- .addOptionsModification(this::configurationForProgramCompilation)
- .addInnerClasses(ObjectsTest.class)
- .addProgramClassFileData(dumpAndroidRUtilsObjectsMethods())
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- (apiLevel, keepRules, shrink) ->
- buildDesugaredLibrary(
- apiLevel,
- keepRules,
- shrink,
- ImmutableList.of(),
- this::configurationForLibraryCompilation),
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
- .inspect(this::inspect)
- .run(parameters.getRuntime(), TestClass.class)
- .assertSuccessWithOutput(EXPECTED_OUTPUT);
- }
-
- @Test
- public void testR8() throws Exception {
- Assume.assumeTrue(parameters.getRuntime().isDex());
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForR8(parameters.getBackend())
- .addLibraryFiles(androidJar)
- .addOptionsModification(this::configurationForProgramCompilation)
- .addInnerClasses(ObjectsTest.class)
+ public void testObjects() throws Throwable {
+ Assume.assumeFalse(
+ "Method is absent on JDK8",
+ parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.R)
+ && parameters.isCfRuntime(CfVm.JDK8));
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
+ .addProgramClassFileData(ImmutableList.of(dumpAndroidRUtilsObjectsMethods()))
.addKeepMainRule(TestClass.class)
- .addProgramClassFileData(dumpAndroidRUtilsObjectsMethods())
.enableInliningAnnotations()
.noMinification()
.addKeepRules("-keep class AndroidRUtilsObjectsMethods { *; }")
.addKeepRules("-neverinline class AndroidRUtilsObjectsMethods { *; }")
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
.compile()
- .addDesugaredCoreLibraryRunClassPath(
- (apiLevel, keepRules, shrink) ->
- buildDesugaredLibrary(
- apiLevel,
- keepRules,
- shrink,
- ImmutableList.of(),
- this::configurationForLibraryCompilation),
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
.inspect(this::inspect)
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PriorityQueueSubclassTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PriorityQueueSubclassTest.java
index 72c8729..2b687bd 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PriorityQueueSubclassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PriorityQueueSubclassTest.java
@@ -4,8 +4,12 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+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.utils.BooleanUtils;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import java.util.List;
import java.util.PriorityQueue;
import java.util.stream.Stream;
@@ -18,52 +22,31 @@
public class PriorityQueueSubclassTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
- private final boolean shrinkDesugaredLibrary;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ @Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
return buildParameters(
- BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ DEFAULT_SPECIFICATIONS);
}
- public PriorityQueueSubclassTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ public PriorityQueueSubclassTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
- public void testPriorityQueueD8() throws Exception {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForD8()
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(PriorityQueueSubclassTest.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
- .run(parameters.getRuntime(), Executor.class)
- .assertSuccessWithOutputLines("1");
- }
-
- @Test
- public void testPriorityQueueR8() throws Exception {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- testForR8(Backend.DEX)
- .addLibraryFiles(getLibraryFile())
- .addInnerClasses(PriorityQueueSubclassTest.class)
- .setMinApi(parameters.getApiLevel())
+ public void testPriorityQueue() throws Throwable {
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addInnerClasses(getClass())
.addKeepClassAndMembersRules(Executor.class)
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
.run(parameters.getRuntime(), Executor.class)
.assertSuccessWithOutputLines("1");
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramInterfaceWithLibraryMethod.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramInterfaceWithLibraryMethod.java
index daf4da7..18ccc4e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramInterfaceWithLibraryMethod.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramInterfaceWithLibraryMethod.java
@@ -3,134 +3,68 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.desugar.desugaredlibrary;
-import static org.junit.Assume.assumeTrue;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.SPECIFICATIONS_WITH_CF2CF;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CustomLibrarySpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.ZipUtils.ZipBuilder;
-import java.nio.file.Files;
-import java.nio.file.Path;
+import java.util.List;
import java.util.function.Consumer;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameter;
import org.junit.runners.Parameterized.Parameters;
// See b/204518518.
@RunWith(Parameterized.class)
public class ProgramInterfaceWithLibraryMethod extends DesugaredLibraryTestBase {
- @Parameter(0)
- public TestParameters parameters;
-
private static final String EXPECTED_RESULT = StringUtils.lines("Hello, world!");
- private static Path CUSTOM_LIB_DEX;
- private static Path CUSTOM_LIB_CF;
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
+ private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ SPECIFICATIONS_WITH_CF2CF);
}
- @BeforeClass
- public static void compileCustomLib() throws Exception {
- CUSTOM_LIB_DEX = getStaticTemp().newFolder().toPath().resolve("customLibDex.jar");
- testForD8(getStaticTemp())
- .addProgramClasses(LibraryClass.class)
- .setMinApi(AndroidApiLevel.B)
- .compile()
- .writeToZip(CUSTOM_LIB_DEX);
- CUSTOM_LIB_CF = getStaticTemp().newFolder().toPath().resolve("customLibCf.jar");
- ZipBuilder.builder(CUSTOM_LIB_CF)
- .addBytes(
- DescriptorUtils.getPathFromJavaType(LibraryClass.class),
- Files.readAllBytes(ToolHelper.getClassFileForTestClass(LibraryClass.class)))
- .build();
+ public ProgramInterfaceWithLibraryMethod(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
+ this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
- public void testD8() throws Exception {
- assumeTrue(parameters.isDexRuntime());
- testForD8()
- .addLibraryFiles(getLibraryFile())
- .addLibraryClasses(LibraryClass.class)
- .setMinApi(parameters.getApiLevel())
+ public void testProgramInterfaceWithLibraryMethod() throws Throwable {
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
.addProgramClasses(Executor.class, ProgramInterface.class, ProgramClass.class)
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compile()
- .addRunClasspathFiles(CUSTOM_LIB_DEX)
- .run(parameters.getRuntime(), Executor.class)
- .applyIf(
- parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N),
- r -> r.assertSuccessWithOutput(EXPECTED_RESULT),
- r -> r.assertFailureWithErrorThatThrows(AbstractMethodError.class));
- }
-
- @Test
- public void testD8CfToCf() throws Exception {
- Path jar =
- testForD8(Backend.CF)
- .addLibraryFiles(getLibraryFile())
- .addLibraryClasses(LibraryClass.class)
- .addProgramClasses(Executor.class, ProgramInterface.class, ProgramClass.class)
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compile()
- .writeToZip();
- if (parameters.getRuntime().isDex()) {
- testForD8()
- .addProgramFiles(jar)
- .setMinApi(parameters.getApiLevel())
- .disableDesugaring()
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary, parameters.getApiLevel())
- .addRunClasspathFiles(CUSTOM_LIB_DEX)
- .run(parameters.getRuntime(), Executor.class)
- .applyIf(
- parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N),
- r -> r.assertSuccessWithOutput(EXPECTED_RESULT),
- r -> r.assertFailureWithErrorThatThrows(AbstractMethodError.class));
- } else {
- testForJvm()
- .addProgramFiles(jar)
- .addRunClasspathFiles(getDesugaredLibraryInCF(parameters, options -> {}))
- .addRunClasspathFiles(CUSTOM_LIB_CF)
- .run(parameters.getRuntime(), Executor.class)
- .applyIf(
- parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N),
- r -> r.assertSuccessWithOutput(EXPECTED_RESULT),
- r -> r.assertFailureWithErrorThatThrows(AbstractMethodError.class));
- }
- }
-
- @Test
- public void testR8() throws Exception {
- testForR8(parameters.getBackend())
- .addLibraryFiles(getLibraryFile())
- .addLibraryClasses(LibraryClass.class)
- .setMinApi(parameters.getApiLevel())
- .addProgramClasses(Executor.class, ProgramInterface.class, ProgramClass.class)
+ .setCustomLibrarySpecification(
+ new CustomLibrarySpecification(LibraryClass.class, AndroidApiLevel.B))
.addKeepMainRule(Executor.class)
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .compile()
- .addRunClasspathFiles(parameters.isDexRuntime() ? CUSTOM_LIB_DEX : CUSTOM_LIB_CF)
.run(parameters.getRuntime(), Executor.class)
.applyIf(
parameters.isDexRuntime()
&& parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N),
r -> r.assertSuccessWithOutput(EXPECTED_RESULT),
- r -> r.assertFailureWithErrorThatThrows(NoSuchMethodError.class));
+ r -> {
+ if (compilationSpecification.isProgramShrink()) {
+ r.assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+ } else {
+ r.assertFailureWithErrorThatThrows(AbstractMethodError.class);
+ }
+ });
}
static class Executor {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
index 20e5408..8ed7907 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ProgramRewritingTest.java
@@ -4,30 +4,34 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static com.android.tools.r8.ToolHelper.DESUGARED_JDK_8_LIB_JAR;
+import static com.android.tools.r8.ToolHelper.UNDESUGARED_JDK_11_LIB_JAR;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK11;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertFalse;
-import com.android.tools.r8.D8TestCompileResult;
-import com.android.tools.r8.D8TestRunResult;
-import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm;
+import com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
-import java.nio.file.Path;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableSet;
import java.nio.file.Paths;
-import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
-import org.junit.Assume;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -39,66 +43,85 @@
private static final String TEST_CLASS = "stream.ProgramRewritingTestClass";
private final TestParameters parameters;
- private final boolean shrinkDesugaredLibrary;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}")
+ @Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
+ LibraryDesugaringSpecification jdk8CoreLambdaStubs =
+ new LibraryDesugaringSpecification(
+ "JDK8_CL",
+ ImmutableSet.of(
+ DESUGARED_JDK_8_LIB_JAR,
+ ToolHelper.DESUGAR_LIB_CONVERSIONS,
+ ToolHelper.getCoreLambdaStubs()),
+ JDK8.getSpecification(),
+ ImmutableSet.of(ToolHelper.getAndroidJar(AndroidApiLevel.O)),
+ "");
+ LibraryDesugaringSpecification jdk11CoreLambdaStubs =
+ new LibraryDesugaringSpecification(
+ "JDK11_CL",
+ ImmutableSet.of(
+ UNDESUGARED_JDK_11_LIB_JAR,
+ ToolHelper.DESUGAR_LIB_CONVERSIONS,
+ ToolHelper.getCoreLambdaStubs()),
+ JDK11.getSpecification(),
+ ImmutableSet.of(ToolHelper.getAndroidJar(AndroidApiLevel.R)),
+ "");
return buildParameters(
- BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ ImmutableList.of(JDK8, JDK11, jdk8CoreLambdaStubs, jdk11CoreLambdaStubs),
+ DEFAULT_SPECIFICATIONS);
}
- public ProgramRewritingTest(boolean shrinkDesugaredLibrary, TestParameters parameters) {
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ public ProgramRewritingTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
- public void testProgramD8() throws Exception {
- ArrayList<Path> coreLambdaStubs = new ArrayList<>();
- coreLambdaStubs.add(ToolHelper.getCoreLambdaStubs());
- for (Boolean coreLambdaStubsActive : BooleanUtils.values()) {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- D8TestCompileResult compileResult =
- testForD8()
- .addLibraryFiles(getLibraryFile())
- .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .inspect(this::checkRewrittenInvokes);
- if (parameters.getApiLevel().getLevel() < AndroidApiLevel.O.getLevel()) {
- compileResult.addRunClasspathFiles(
- buildCoreLambdaDesugaredLibrary(
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary,
- coreLambdaStubsActive,
- coreLambdaStubs));
- }
- D8TestRunResult runResult =
- compileResult.run(parameters.getRuntime(), TEST_CLASS).assertSuccess();
- assertResultIsCorrect(runResult.getStdOut(), runResult.getStdErr(), keepRuleConsumer.get());
- }
- }
-
- private Path buildCoreLambdaDesugaredLibrary(
- AndroidApiLevel apiLevel,
- String keepRules,
- boolean shrink,
- boolean coreLambdaStubsActive,
- ArrayList<Path> coreLambdaStubs) {
- return coreLambdaStubsActive
- ? buildDesugaredLibrary(apiLevel, keepRules, shrink, coreLambdaStubs)
- : buildDesugaredLibrary(apiLevel, keepRules, shrink);
+ public void testRewriting() throws Throwable {
+ Box<String> keepRules = new Box<>();
+ SingleTestRunResult<?> run =
+ testForDesugaredLibrary(
+ parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
+ .addKeepMainRule(TEST_CLASS)
+ .applyIf(
+ compilationSpecification.isProgramShrink(),
+ b ->
+ b.addOptionsModification(
+ options -> {
+ // TODO(b/140233505): Allow devirtualization once fixed.
+ options.enableDevirtualization = false;
+ }))
+ .compile()
+ .inspect(this::checkRewrittenInvokes)
+ .inspectKeepRules(
+ kr -> {
+ if (parameters.getApiLevel().getLevel() < AndroidApiLevel.N.getLevel()) {
+ keepRules.set(String.join("\n", kr));
+ } else {
+ assert kr == null;
+ keepRules.set("");
+ }
+ })
+ .run(parameters.getRuntime(), TEST_CLASS);
+ assertResultIsCorrect(run.getStdOut(), run.getStdErr(), keepRules.get());
}
private void assertResultIsCorrect(String stdOut, String stdErr, String keepRules) {
if (parameters.getApiLevel().getLevel() < AndroidApiLevel.N.getLevel()) {
- if (!shrinkDesugaredLibrary) {
+ if (compilationSpecification.isL8Shrink()) {
+ assertGeneratedKeepRulesAreCorrect(keepRules);
+ } else {
// When shrinking the class names are not printed correctly anymore due to minification.
assertLines2By2Correct(stdOut);
}
- assertGeneratedKeepRulesAreCorrect(keepRules);
}
if (parameters.getRuntime().asDex().getVm().isOlderThanOrEqual(DexVm.ART_4_4_4_HOST)) {
// Flaky: There might be a missing method on lambda deserialization.
@@ -110,39 +133,6 @@
}
}
- @Test
- public void testProgramR8() throws Exception {
- Assume.assumeTrue(
- "TODO(b/139451198): Make the test run with new SDK.",
- parameters.getApiLevel().getLevel() < AndroidApiLevel.O.getLevel());
- for (Boolean minifying : BooleanUtils.values()) {
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- R8TestRunResult runResult =
- testForR8(parameters.getBackend())
- .addLibraryFiles(getLibraryFile())
- .minification(minifying)
- .addKeepMainRule(TEST_CLASS)
- .addProgramFiles(Paths.get(ToolHelper.EXAMPLES_JAVA9_BUILD_DIR + "stream.jar"))
- .setMinApi(parameters.getApiLevel())
- .addOptionsModification(
- options -> {
- // TODO(b/140233505): Allow devirtualization once fixed.
- options.enableDevirtualization = false;
- })
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .compile()
- .inspect(this::checkRewrittenInvokes)
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary)
- .run(parameters.getRuntime(), TEST_CLASS)
- .assertSuccess();
- assertResultIsCorrect(runResult.getStdOut(), runResult.getStdErr(), keepRuleConsumer.get());
- }
- }
-
private void checkRewrittenInvokes(CodeInspector inspector) {
if (parameters.getApiLevel().getLevel() >= AndroidApiLevel.N.getLevel()) {
return;
@@ -213,6 +203,6 @@
"}",
"-keep class j$.util.stream.IntStream",
"-keep class j$.util.stream.Stream");
- assertEquals(expectedResult, keepRules);
+ assertEquals(expectedResult.trim(), keepRules.trim());
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PseudoPlatformApiTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PseudoPlatformApiTest.java
index 3c1716a..0901073 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PseudoPlatformApiTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/PseudoPlatformApiTest.java
@@ -97,13 +97,14 @@
@Test
public void testD8WithLibraryDesugaringOemClassNotPresent() throws Exception {
+ // Enable library desugaring with an effective min API of 1.
testForD8(parameters.getBackend())
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
.addLibraryFiles(androidJarAdditions())
.addProgramClasses(ProgramClass.class)
.setMinApi(AndroidApiLevel.H_MR2)
- // Enable library desugaring with an effective min API of 1.
- .enableLibraryDesugaring(LibraryDesugaringTestConfiguration.forApiLevel(AndroidApiLevel.B))
+ .enableCoreLibraryDesugaring(
+ LibraryDesugaringTestConfiguration.forApiLevel(AndroidApiLevel.B))
.addRunClasspathFiles(androidJarAdditionsDex())
.run(parameters.getRuntime(), ProgramClass.class)
.assertSuccessWithOutputLines("DEFAULT-X", "Y-DEFAULT");
@@ -111,13 +112,14 @@
@Test
public void testD8WithLibraryDesugaringOemClassPresent() throws Exception {
+ // Enable library desugaring with an effective min API of 1.
testForD8(parameters.getBackend())
.addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
.addLibraryFiles(androidJarAdditions())
.addProgramClasses(ProgramClass.class)
.setMinApi(AndroidApiLevel.H_MR2)
- // Enable library desugaring with an effective min API of 1.
- .enableLibraryDesugaring(LibraryDesugaringTestConfiguration.forApiLevel(AndroidApiLevel.B))
+ .enableCoreLibraryDesugaring(
+ LibraryDesugaringTestConfiguration.forApiLevel(AndroidApiLevel.B))
.addRunClasspathFiles(androidJarAdditionsDex())
.addRunClasspathFiles(oemDex())
.run(parameters.getRuntime(), ProgramClass.class)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ClockAPIConversionTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ClockAPIConversionTest.java
index 29a21ad..53edf4c 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ClockAPIConversionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ClockAPIConversionTest.java
@@ -6,8 +6,11 @@
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.assertEquals;
+import static org.junit.Assume.assumeTrue;
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.CustomLibrarySpecification;
@@ -29,7 +32,11 @@
private final CompilationSpecification compilationSpecification;
private static final AndroidApiLevel MIN_SUPPORTED = AndroidApiLevel.O;
- private static final String EXPECTED_RESULT = StringUtils.lines("Z", "Z", "true", "Z", "Z");
+ private static final String EXPECTED_RESULT =
+ StringUtils.lines("Z", "Z", "true", "Z", "Z", "true", "true", "true", "true", "true", "true");
+ private static final String DESUGARED_LIBRARY_EXPECTED_RESULT =
+ StringUtils.lines(
+ "Z", "Z", "true", "Z", "Z", "true", "true", "false", "false", "true", "true");
@Parameters(name = "{0}, spec: {1}, {2}")
public static List<Object[]> data() {
@@ -56,6 +63,41 @@
new CustomLibrarySpecification(CustomLibClass.class, MIN_SUPPORTED))
.addKeepMainRule(Executor.class)
.run(parameters.getRuntime(), Executor.class)
+ .assertSuccessWithOutput(DESUGARED_LIBRARY_EXPECTED_RESULT);
+ }
+
+ @Test
+ public void testD8() throws Throwable {
+ // Run a D8 test without desugared library on all runtimes which natively supports java.time to
+ // ensure the expectations. The API level check is just to not run the same test repeatedly.
+ assertEquals(AndroidApiLevel.O, MIN_SUPPORTED);
+ assumeTrue(
+ parameters.getApiLevel().isEqualTo(AndroidApiLevel.N_MR1)
+ && parameters.isDexRuntime()
+ && parameters.asDexRuntime().getVersion().isNewerThanOrEqual(Version.V8_1_0)
+ && compilationSpecification == CompilationSpecification.D8_L8DEBUG);
+ testForD8(parameters.getBackend())
+ .addProgramClasses(Executor.class, CustomLibClass.class)
+ .setMinApi(MIN_SUPPORTED)
+ .run(parameters.getRuntime(), Executor.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ @Test
+ public void testR8() throws Throwable {
+ // Run a R8 test without desugared library on all runtimes which natively supports java.time to
+ // ensure the expectations. The API level check is just to not run the same test repeatedly.
+ assertEquals(AndroidApiLevel.O, MIN_SUPPORTED);
+ assumeTrue(
+ parameters.getApiLevel().isEqualTo(AndroidApiLevel.N_MR1)
+ && parameters.isDexRuntime()
+ && parameters.asDexRuntime().getVersion().isNewerThanOrEqual(Version.V8_1_0)
+ && compilationSpecification == CompilationSpecification.D8_L8DEBUG);
+ testForR8(parameters.getBackend())
+ .addProgramClasses(Executor.class, CustomLibClass.class)
+ .addKeepMainRule(Executor.class)
+ .setMinApi(MIN_SUPPORTED)
+ .run(parameters.getRuntime(), Executor.class)
.assertSuccessWithOutput(EXPECTED_RESULT);
}
@@ -71,6 +113,12 @@
System.out.println(localClock == clock2);
System.out.println(CustomLibClass.getClocks()[0].getZone());
System.out.println(CustomLibClass.getClockss()[0][0].getZone());
+ System.out.println(clock1.equals(CustomLibClass.getClock()));
+ System.out.println(localClock.equals(Clock.systemUTC()));
+ System.out.println(localClock.equals(clock1)); // Prints false with desugared library.
+ System.out.println(clock1.equals(localClock)); // Prints false with desugared library.
+ System.out.println(clock1.equals(CustomLibClass.getClocks()[0]));
+ System.out.println(clock1.equals(CustomLibClass.getClockss()[0][0]));
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionAndMergeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionAndMergeTest.java
index 1846a68..ed4b818 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionAndMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionAndMergeTest.java
@@ -63,7 +63,7 @@
private Path buildClass(Class<?> cls) throws Exception {
return testForD8()
- .addLibraryFiles(getLibraryFile())
+ .addLibraryFiles(libraryDesugaringSpecification.getLibraryFiles())
.setMinApi(parameters.getApiLevel())
.addProgramClasses(cls)
.enableCoreLibraryDesugaring(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperEqualityTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperEqualityTest.java
new file mode 100644
index 0000000..1353145
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/WrapperEqualityTest.java
@@ -0,0 +1,241 @@
+// 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.conversiontests;
+
+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.assertEquals;
+import static org.junit.Assume.assumeTrue;
+
+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.CustomLibrarySpecification;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
+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 WrapperEqualityTest extends DesugaredLibraryTestBase {
+
+ private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
+
+ private static final AndroidApiLevel MIN_SUPPORTED = AndroidApiLevel.N;
+ private static final String EXPECTED_RESULT =
+ StringUtils.lines(
+ "true", "true", "true", "true", "true", "true", "true", "true", "false", "false", "1",
+ "1", "2", "2", "1", "1", "1", "0", "true", "true", "true", "true");
+ private static final String DESUGARED_LIBRARY_EXPECTED_RESULT =
+ StringUtils.lines(
+ "true", "true", "true", "true", "false", "true", "false", "true", "false", "false", "1",
+ "1", "2", "2", "1", "1", "1", "0", "false", "true", "false", "true");
+
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getConversionParametersUpToExcluding(MIN_SUPPORTED),
+ getJdk8Jdk11(),
+ DEFAULT_SPECIFICATIONS);
+ }
+
+ public WrapperEqualityTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
+ this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
+ }
+
+ @Test
+ public void test() throws Throwable {
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addProgramClasses(Executor.class)
+ .setCustomLibrarySpecification(
+ new CustomLibrarySpecification(CustomLibClass.class, MIN_SUPPORTED))
+ .addKeepMainRule(Executor.class)
+ .compile()
+ .run(parameters.getRuntime(), Executor.class)
+ .assertSuccessWithOutput(DESUGARED_LIBRARY_EXPECTED_RESULT);
+ }
+
+ @Test
+ public void testD8() throws Throwable {
+ // Run a D8 test without desugared library on all runtimes which natively supports
+ // java.util.function to ensure the expectations. The API level check is just to not run the
+ // same test repeatedly.
+ assertEquals(AndroidApiLevel.N, MIN_SUPPORTED);
+ assumeTrue(
+ parameters.getApiLevel().isEqualTo(AndroidApiLevel.M)
+ && parameters.isDexRuntime()
+ && parameters.asDexRuntime().getVersion().isNewerThanOrEqual(Version.V8_1_0)
+ && compilationSpecification == CompilationSpecification.D8_L8DEBUG);
+ testForD8(parameters.getBackend())
+ .addProgramClasses(Executor.class, CustomLibClass.class)
+ .compile()
+ .run(parameters.getRuntime(), Executor.class)
+ .assertSuccessWithOutput(EXPECTED_RESULT);
+ }
+
+ static class Executor {
+
+ public static void main(String[] args) {
+ Consumer<Boolean> consumer = b -> {};
+ Supplier<Boolean> supplier = () -> Boolean.TRUE;
+ // Prints true for desugared library as the same wrapper is used for both arguments.
+ System.out.println(CustomLibClass.same(consumer, consumer));
+ System.out.println(CustomLibClass.equals(consumer, consumer));
+ // Prints true for desugared library as the same wrapper is used for both arguments.
+ System.out.println(CustomLibClass.same(supplier, supplier));
+ System.out.println(CustomLibClass.equals(supplier, supplier));
+
+ CustomLibClass.setConsumer(consumer);
+ CustomLibClass.setSupplier(supplier);
+ System.out.println(CustomLibClass.same(consumer));
+ System.out.println(CustomLibClass.equals(consumer));
+ System.out.println(CustomLibClass.same(supplier));
+ System.out.println(CustomLibClass.equals(supplier));
+ System.out.println(CustomLibClass.equalsWithObject(consumer, new HashMap<>()));
+ System.out.println(CustomLibClass.equalsWithObject(supplier, new ArrayList<>()));
+
+ CustomLibClass.register(consumer, new Object());
+ System.out.println(CustomLibClass.registrations());
+ CustomLibClass.register(consumer, new Object());
+ System.out.println(CustomLibClass.registrations());
+ CustomLibClass.register(supplier, new Object());
+ System.out.println(CustomLibClass.registrations());
+ CustomLibClass.register(supplier, new Object());
+ System.out.println(CustomLibClass.registrations());
+ System.out.println(CustomLibClass.suppliers());
+ System.out.println(CustomLibClass.consumers());
+ CustomLibClass.unregister(consumer);
+ System.out.println(CustomLibClass.registrations());
+ CustomLibClass.unregister(supplier);
+ System.out.println(CustomLibClass.registrations());
+
+ // Prints false for desugared library as wrappers does not keep identity.
+ System.out.println(
+ CustomLibClass.getConsumerFromPlatform() == CustomLibClass.getConsumerFromPlatform());
+ System.out.println(
+ CustomLibClass.getConsumerFromPlatform()
+ .equals(CustomLibClass.getConsumerFromPlatform()));
+ // Prints false for desugared library as wrappers does not keep identity.
+ System.out.println(
+ CustomLibClass.getSupplierFromPlatform() == CustomLibClass.getSupplierFromPlatform());
+ System.out.println(
+ CustomLibClass.getSupplierFromPlatform()
+ .equals(CustomLibClass.getSupplierFromPlatform()));
+ }
+ }
+
+ // This class will be put at compilation time as library and on the runtime class path.
+ // This class is convenient for easy testing. Each method plays the role of methods in the
+ // platform APIs for which argument/return values need conversion.
+ static class CustomLibClass {
+ private static final Map<Object, Object> map = new HashMap<>();
+ private static final Consumer<Boolean> consumer = b -> {};
+ private static final Supplier<Boolean> supplier = () -> Boolean.TRUE;
+
+ private static Consumer<Boolean> appConsumer;
+ private static Supplier<Boolean> appSupplier;
+
+ public static boolean equals(Consumer<Boolean> consumer1, Consumer<Boolean> consumer2) {
+ return consumer1.equals(consumer2) && consumer2.equals(consumer1);
+ }
+
+ public static boolean equals(Supplier<Boolean> supplier1, Supplier<Boolean> supplier2) {
+ return supplier1.equals(supplier2) && supplier2.equals(supplier1);
+ }
+
+ public static boolean same(Consumer<Boolean> consumer1, Consumer<Boolean> consumer2) {
+ return consumer1.equals(consumer2) && consumer2.equals(consumer1);
+ }
+
+ public static boolean same(Supplier<Boolean> supplier1, Supplier<Boolean> supplier2) {
+ return supplier1.equals(supplier2) && supplier2.equals(supplier1);
+ }
+
+ public static void setConsumer(Consumer<Boolean> consumer) {
+ appConsumer = consumer;
+ }
+
+ public static void setSupplier(Supplier supplier) {
+ appSupplier = supplier;
+ }
+
+ public static boolean equals(Consumer<Boolean> consumer) {
+ return consumer.equals(appConsumer) && appConsumer.equals(consumer);
+ }
+
+ public static boolean equals(Supplier<Boolean> supplier) {
+ return supplier.equals(appSupplier) && appSupplier.equals(supplier);
+ }
+
+ public static boolean same(Consumer<Boolean> consumer) {
+ return appConsumer == consumer;
+ }
+
+ public static boolean same(Supplier supplier) {
+ return appSupplier == supplier;
+ }
+
+ public static boolean equalsWithObject(Consumer<Boolean> consumer, Object object) {
+ return consumer.equals(object);
+ }
+
+ public static boolean equalsWithObject(Supplier<Boolean> supplier, Object object) {
+ return supplier.equals(object);
+ }
+
+ public static void register(Consumer<Boolean> listener, Object context) {
+ map.put(listener, context);
+ }
+
+ public static void unregister(Consumer<Boolean> listener) {
+ map.remove(listener);
+ }
+
+ public static void register(Supplier<Boolean> listener, Object context) {
+ map.put(listener, context);
+ }
+
+ public static void unregister(Supplier<Boolean> listener) {
+ map.remove(listener);
+ }
+
+ public static int registrations() {
+ return map.size();
+ }
+
+ public static long consumers() {
+ return map.keySet().stream().filter(k -> k instanceof Consumer).count();
+ }
+
+ public static long suppliers() {
+ return map.keySet().stream().filter(k -> k instanceof Supplier).count();
+ }
+
+ public static Supplier<Boolean> getSupplierFromPlatform() {
+ return supplier;
+ }
+
+ public static Consumer<Boolean> getConsumerFromPlatform() {
+ return consumer;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeAbstractTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeAbstractTests.java
index bc89176..6cf5f77 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeAbstractTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeAbstractTests.java
@@ -176,7 +176,7 @@
};
static final String[] RAW_TEMPORAL_SUCCESSES_IF_BRIDGE =
new String[] {"tck.java.time.TestIsoChronology"};
- static final String[] RAW_TEMPORAL_SUCCESSES_BUT_12 =
+ static final String[] RAW_TEMPORAL_SUCCESSES_UP_TO_11 =
new String[] {"test.java.time.temporal.TestIsoWeekFields"};
static final String[] FORMAT_CHRONO_SUCCESSES =
new String[] {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeRawTemporalTests.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeRawTemporalTests.java
index 2b9b95c..aa1f537 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeRawTemporalTests.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/jdktests/Jdk11TimeRawTemporalTests.java
@@ -28,9 +28,9 @@
@Test
public void testTime() throws Exception {
testTime(RAW_TEMPORAL_SUCCESSES);
- if (!parameters.getDexRuntimeVersion().isEqualTo(Version.V12_0_0)) {
+ if (parameters.getDexRuntimeVersion().isOlderThan(Version.V12_0_0)) {
// In 12 some ISO is supported that other versions do not support.
- testTime(RAW_TEMPORAL_SUCCESSES_BUT_12);
+ testTime(RAW_TEMPORAL_SUCCESSES_UP_TO_11);
}
// The bridge is always present with JDK11 due to partial desugaring between 26 and 33.
// On JDK8 the bridge is absent in between 26 and 33.
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
index b58b4e1..3458390 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
@@ -6,35 +6,29 @@
import static com.android.tools.r8.KotlinCompilerTool.KotlinCompilerVersion.KOTLINC_1_3_72;
import static com.android.tools.r8.KotlinTestBase.getCompileMemoizer;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.DEFAULT_SPECIFICATIONS;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.JDK8;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotNull;
-import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.D8TestRunResult;
-import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase.KotlinCompileMemoizer;
import com.android.tools.r8.KotlinTestParameters;
-import com.android.tools.r8.R8FullTestBuilder;
-import com.android.tools.r8.R8TestCompileResult;
-import com.android.tools.r8.R8TestRunResult;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestCompileResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
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.kotlin.KotlinMetadataWriter;
-import com.android.tools.r8.kotlin.metadata.KotlinMetadataTestBase;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
-import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import java.io.File;
+import com.google.common.collect.ImmutableList;
import java.nio.file.Paths;
import java.util.List;
import kotlinx.metadata.jvm.KotlinClassMetadata;
@@ -49,27 +43,72 @@
private static final String PKG = KotlinMetadataTest.class.getPackage().getName();
private static final String EXPECTED_OUTPUT = "Wuhuu, my special day is: 1997-8-29-2-14";
- private final TestParameters parameters;
private final KotlinTestParameters kotlinParameters;
private final KotlinCompiler kotlinc;
- private final boolean shrinkDesugaredLibrary;
- @Parameters(name = "{0}, {1}, shrinkDesugaredLibrary: {2}")
+ private final TestParameters parameters;
+ private final CompilationSpecification compilationSpecification;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+
+ @Parameters(name = "{0}, kotlin: {1}, spec: {2}, {3}")
public static List<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
getKotlinTestParameters().withAllCompilersAndTargetVersions().build(),
- BooleanUtils.values());
+ ImmutableList.of(LibraryDesugaringSpecification.JDK11),
+ DEFAULT_SPECIFICATIONS);
}
public KotlinMetadataTest(
TestParameters parameters,
KotlinTestParameters kotlinParameters,
- boolean shrinkDesugaredLibrary) {
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
this.kotlinParameters = kotlinParameters;
this.kotlinc = kotlinParameters.getCompiler();
- this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
+ this.compilationSpecification = compilationSpecification;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ }
+
+ @Test
+ public void test() throws Throwable {
+ if (parameters.getRuntime().isCf()) {
+ testForRuntime(parameters)
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinParameters))
+ .addProgramFiles(kotlinc.getKotlinStdlibJar())
+ .addProgramFiles(kotlinc.getKotlinReflectJar())
+ .run(parameters.getRuntime(), PKG + ".MainKt")
+ .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
+ return;
+ }
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinParameters))
+ .addProgramFiles(kotlinc.getKotlinStdlibJar())
+ .addProgramFiles(kotlinc.getKotlinReflectJar())
+ .applyIf(
+ compilationSpecification.isProgramShrink(),
+ builder -> builder.addProgramFiles(kotlinc.getKotlinAnnotationJar()))
+ .addOptionsModification(
+ options -> {
+ options.testing.enableD8ResourcesPassThrough = true;
+ options.dataResourceConsumer = options.programConsumer.getDataResourceConsumer();
+ })
+ .addKeepMainRule(PKG + ".MainKt")
+ .addKeepAllClassesRule()
+ .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+ .allowDiagnosticMessages()
+ .allowUnusedDontWarnKotlinReflectJvmInternal(
+ kotlinParameters.getCompiler().isNot(KOTLINC_1_3_72))
+ .compile()
+ .inspect(
+ i -> {
+ if (requiresTimeDesugaring(parameters, libraryDesugaringSpecification != JDK8)) {
+ inspectRewrittenMetadata(i);
+ }
+ })
+ .run(parameters.getRuntime(), PKG + ".MainKt")
+ .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
}
private static KotlinCompileMemoizer compiledJars =
@@ -80,98 +119,6 @@
DescriptorUtils.getBinaryNameFromJavaType(PKG),
"Main" + FileUtils.KT_EXTENSION));
- @Test
- public void testCf() throws Exception {
- assumeTrue(parameters.getRuntime().isCf());
- testForRuntime(parameters)
- .addProgramFiles(compiledJars.getForConfiguration(kotlinParameters))
- .addProgramFiles(kotlinc.getKotlinStdlibJar())
- .addProgramFiles(kotlinc.getKotlinReflectJar())
- .run(parameters.getRuntime(), PKG + ".MainKt")
- .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
- }
-
- @Test
- public void testTimeD8() throws Exception {
- assumeTrue(parameters.getRuntime().isDex());
- KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
- final File output = temp.newFile("output.zip");
- final D8TestRunResult d8TestRunResult =
- testForD8()
- .addLibraryFiles(getLibraryFile())
- .addProgramFiles(compiledJars.getForConfiguration(kotlinParameters))
- .addProgramFiles(kotlinc.getKotlinStdlibJar())
- .addProgramFiles(kotlinc.getKotlinReflectJar())
- .setProgramConsumer(new ArchiveConsumer(output.toPath(), true))
- .setMinApi(parameters.getApiLevel())
- .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
- .addOptionsModification(
- options -> {
- options.testing.enableD8ResourcesPassThrough = true;
- options.dataResourceConsumer = options.programConsumer.getDataResourceConsumer();
- })
- .compile()
- .addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- false)
- .run(parameters.getRuntime(), PKG + ".MainKt")
- .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
- if (requiresTimeDesugaring(parameters)) {
- d8TestRunResult.inspect(this::inspectRewrittenMetadata);
- }
- }
-
- @Test
- public void testTimeR8() throws Exception {
- boolean desugarLibrary = parameters.isDexRuntime() && requiresTimeDesugaring(parameters);
- final R8FullTestBuilder testBuilder =
- testForR8(parameters.getBackend())
- .addLibraryFiles(getLibraryFile())
- .addProgramFiles(compiledJars.getForConfiguration(kotlinParameters))
- .addProgramFiles(kotlinc.getKotlinStdlibJar())
- .addProgramFiles(kotlinc.getKotlinReflectJar())
- .addProgramFiles(kotlinc.getKotlinAnnotationJar())
- .addKeepMainRule(PKG + ".MainKt")
- .addKeepAllClassesRule()
- .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
- .setMinApi(parameters.getApiLevel())
- .allowDiagnosticMessages()
- .allowUnusedDontWarnKotlinReflectJvmInternal(
- kotlinParameters.getCompiler().isNot(KOTLINC_1_3_72));
- KeepRuleConsumer keepRuleConsumer = null;
- if (desugarLibrary) {
- keepRuleConsumer = createKeepRuleConsumer(parameters);
- testBuilder.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer);
- }
- R8TestCompileResult compileResult =
- testBuilder
- .compile()
- .assertNoErrorMessages()
- // -keepattributes Signature is added in kotlin-reflect from version 1.4.20.
- .applyIf(
- kotlinParameters.getCompiler().isNot(KOTLINC_1_3_72),
- TestBase::verifyAllInfoFromGenericSignatureTypeParameterValidation,
- TestCompileResult::assertNoInfoMessages)
- .apply(KotlinMetadataTestBase::verifyExpectedWarningsFromKotlinReflectAndStdLib);
- if (desugarLibrary) {
- assertNotNull(keepRuleConsumer);
- compileResult.addDesugaredCoreLibraryRunClassPath(
- this::buildDesugaredLibrary,
- parameters.getApiLevel(),
- keepRuleConsumer.get(),
- shrinkDesugaredLibrary);
- }
- final R8TestRunResult r8TestRunResult =
- compileResult
- .run(parameters.getRuntime(), PKG + ".MainKt")
- .assertSuccessWithOutputLines(EXPECTED_OUTPUT);
- if (desugarLibrary) {
- r8TestRunResult.inspect(this::inspectRewrittenMetadata);
- }
- }
-
private void inspectRewrittenMetadata(CodeInspector inspector) {
final ClassSubject clazz =
inspector.clazz("com.android.tools.r8.desugar.desugaredlibrary.kotlin.Skynet");
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
index ff80b66..7c98dbe 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/specification/ConvertExportReadTest.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
+import com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification;
import com.android.tools.r8.ir.desugar.desugaredlibrary.ApiLevelRange;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanTopLevelFlags;
@@ -48,6 +49,8 @@
public void testMultiLevel() throws IOException {
Assume.assumeTrue(ToolHelper.isLocalDevelopment());
+ LibraryDesugaringSpecification legacySpec = LibraryDesugaringSpecification.JDK8;
+
LegacyToHumanSpecificationConverter converter =
new LegacyToHumanSpecificationConverter(Timing.empty());
@@ -56,15 +59,11 @@
MultiAPILevelLegacyDesugaredLibrarySpecification spec =
new MultiAPILevelLegacyDesugaredLibrarySpecificationParser(
options.dexItemFactory(), options.reporter)
- .parseMultiLevelConfiguration(
- StringResource.fromFile(ToolHelper.getDesugarLibJsonForTesting()));
+ .parseMultiLevelConfiguration(StringResource.fromFile(legacySpec.getSpecification()));
MultiAPILevelHumanDesugaredLibrarySpecification humanSpec1 =
converter.convertAllAPILevels(
- spec,
- ToolHelper.getDesugarJDKLibs(),
- ToolHelper.getAndroidJar(getRequiredCompilationAPILevel()),
- options);
+ spec, legacySpec.getDesugarJdkLibs(), legacySpec.getLibraryFiles(), options);
Box<String> json = new Box<>();
MultiAPILevelHumanDesugaredLibrarySpecificationJsonExporter.export(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/CompilationSpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/CompilationSpecification.java
index 3aecfba..0a8d35b 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/CompilationSpecification.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/CompilationSpecification.java
@@ -12,14 +12,17 @@
import java.util.Set;
public enum CompilationSpecification {
- D8_L8DEBUG(false, false, false, DEBUG),
- D8_L8SHRINK(false, true, false, RELEASE),
+ D8_L8DEBUG(false, false, false, false, DEBUG),
+ D8_L8SHRINK(false, true, false, false, RELEASE),
// In theory no build system uses R8_L8DEBUG, for local debugging only.
- R8_L8DEBUG(true, false, false, RELEASE),
- R8_L8SHRINK(true, true, false, RELEASE),
+ R8_L8DEBUG(true, false, false, false, RELEASE),
+ R8_L8SHRINK(true, true, false, false, RELEASE),
// The D8CFTOCF specifications can run either in CF or be dexed afterwards.
- D8CF2CF_L8DEBUG(false, false, true, DEBUG),
- D8CF2CF_L8SHRINK(false, true, true, RELEASE);
+ D8CF2CF_L8DEBUG(false, false, true, false, DEBUG),
+ D8CF2CF_L8SHRINK(false, true, true, true, RELEASE),
+ // Variants with trace reference in dex.
+ D8_L8SHRINK_TR(false, true, false, true, RELEASE),
+ R8_L8SHRINK_TR(true, true, false, true, RELEASE);
public static Set<CompilationSpecification> DEFAULT_SPECIFICATIONS =
ImmutableSet.of(D8_L8DEBUG, D8_L8SHRINK, R8_L8SHRINK);
@@ -29,13 +32,19 @@
private final boolean programShrink;
private final boolean l8Shrink;
private final boolean cfToCf;
+ private final boolean traceReferences;
private final CompilationMode programCompilationMode;
CompilationSpecification(
- boolean programShrink, boolean l8Shrink, boolean cfToCf, CompilationMode mode) {
+ boolean programShrink,
+ boolean l8Shrink,
+ boolean cfToCf,
+ boolean traceReferences,
+ CompilationMode mode) {
this.programShrink = programShrink;
this.l8Shrink = l8Shrink;
this.cfToCf = cfToCf;
+ this.traceReferences = traceReferences;
this.programCompilationMode = mode;
}
@@ -54,4 +63,8 @@
public boolean isCfToCf() {
return cfToCf;
}
+
+ public boolean isTraceReferences() {
+ return traceReferences;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java
index 7e11cc5..e72e4e7 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/DesugaredLibraryTestBuilder.java
@@ -4,8 +4,6 @@
package com.android.tools.r8.desugar.desugaredlibrary.test;
-import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.D8CF2CF_L8SHRINK;
-
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8TestCompileResult;
import com.android.tools.r8.FeatureSplit;
@@ -29,6 +27,7 @@
import com.android.tools.r8.utils.ConsumerUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.codeinspector.VerticallyMergedClassesInspector;
import com.google.common.base.Charsets;
import java.io.IOException;
import java.nio.file.Path;
@@ -188,6 +187,11 @@
return this;
}
+ public DesugaredLibraryTestBuilder<T> allowUnusedDontWarnKotlinReflectJvmInternal(boolean allow) {
+ withR8TestBuilder(b -> b.allowUnusedDontWarnKotlinReflectJvmInternal(allow));
+ return this;
+ }
+
public DesugaredLibraryTestBuilder<T> allowDiagnosticInfoMessages() {
withR8TestBuilder(R8TestBuilder::allowDiagnosticInfoMessages);
return this;
@@ -198,6 +202,16 @@
return this;
}
+ public DesugaredLibraryTestBuilder<T> addKeepRules(String keepRules) {
+ withR8TestBuilder(b -> b.addKeepRules(keepRules));
+ return this;
+ }
+
+ public DesugaredLibraryTestBuilder<T> addKeepClassAndMembersRules(Class<?>... clazz) {
+ withR8TestBuilder(b -> b.addKeepClassAndMembersRules(clazz));
+ return this;
+ }
+
public DesugaredLibraryTestBuilder<T> addKeepAttributes(String... attributes) {
withR8TestBuilder(b -> b.addKeepAttributes(attributes));
return this;
@@ -234,16 +248,43 @@
return this;
}
+ public DesugaredLibraryTestBuilder<T> enableNeverClassInliningAnnotations() {
+ withR8TestBuilder(R8TestBuilder::enableNeverClassInliningAnnotations);
+ return this;
+ }
+
public DesugaredLibraryTestBuilder<T> enableInliningAnnotations() {
withR8TestBuilder(R8TestBuilder::enableInliningAnnotations);
return this;
}
+ public DesugaredLibraryTestBuilder<T> enableNoVerticalClassMergingAnnotations() {
+ withR8TestBuilder(R8TestBuilder::enableNoVerticalClassMergingAnnotations);
+ return this;
+ }
+
+ public DesugaredLibraryTestBuilder<T> addVerticallyMergedClassesInspector(
+ Consumer<VerticallyMergedClassesInspector> inspector) {
+ withR8TestBuilder(b -> b.addVerticallyMergedClassesInspector(inspector));
+ return this;
+ }
+
public DesugaredLibraryTestBuilder<T> noMinification() {
withR8TestBuilder(R8TestBuilder::noMinification);
return this;
}
+ public DesugaredLibraryTestBuilder<T> enableConstantArgumentAnnotations() {
+ withR8TestBuilder(R8TestBuilder::enableConstantArgumentAnnotations);
+ return this;
+ }
+
+ public DesugaredLibraryTestBuilder<T> applyOnBuilder(
+ Consumer<TestCompilerBuilder<?, ?, ?, ?, ?>> consumer) {
+ consumer.accept(builder);
+ return this;
+ }
+
public DesugaredLibraryTestBuilder<T> applyIf(
boolean apply, Consumer<DesugaredLibraryTestBuilder<T>> consumer) {
if (apply) {
@@ -301,13 +342,11 @@
if (!compilationSpecification.isL8Shrink()) {
return compileDesugaredLibrary(null);
}
- if (!compilationSpecification.isCfToCf()) {
+ if (!compilationSpecification.isTraceReferences()) {
// When going to dex we can get the generated keep rule through the keep rule consumer.
assert keepRuleConsumer != null;
return compileDesugaredLibrary(keepRuleConsumer.get());
}
- // In D8CF2CF_L8SHRINK, we use trace reference to extract the keep rules.
- assert compilationSpecification == D8CF2CF_L8SHRINK;
L8TestCompileResult nonShrunk =
test.testForL8(parameters.getApiLevel(), Backend.CF)
.apply(libraryDesugaringSpecification::configureL8TestBuilder)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
index d4e8e32..65171c1 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/test/LibraryDesugaringSpecification.java
@@ -5,10 +5,10 @@
import static com.android.tools.r8.ToolHelper.DESUGARED_JDK_8_LIB_JAR;
import static com.android.tools.r8.ToolHelper.DESUGARED_LIB_RELEASES_DIR;
+import static com.android.tools.r8.ToolHelper.UNDESUGARED_JDK_11_LIB_JAR;
import com.android.tools.r8.L8TestBuilder;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.desugar.desugaredlibrary.jdk11.DesugaredLibraryJDK11Undesugarer;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
@@ -19,11 +19,6 @@
public class LibraryDesugaringSpecification {
- private static final String RELEASES_DIR = "third_party/openjdk/desugar_jdk_libs_releases/";
- private static final Path UNDESUGARED_JDK_11_LIB_JAR =
- DesugaredLibraryJDK11Undesugarer.undesugaredJarJDK11(
- Paths.get("third_party/openjdk/desugar_jdk_libs_11/desugar_jdk_libs.jar"));
-
// Main head specifications.
public static LibraryDesugaringSpecification JDK8 =
new LibraryDesugaringSpecification(
@@ -74,25 +69,21 @@
new LibraryDesugaringSpecification("1.1.1", AndroidApiLevel.P);
public static final LibraryDesugaringSpecification RELEASED_1_1_5 =
new LibraryDesugaringSpecification("1.1.5", AndroidApiLevel.P);
+
private final String name;
private final Set<Path> desugarJdkLibs;
private final Path specification;
private final Set<Path> libraryFiles;
private final String extraKeepRules;
- private LibraryDesugaringSpecification(
+ public LibraryDesugaringSpecification(
String name, Path desugarJdkLibs, String specificationPath, AndroidApiLevel androidJarLevel) {
this(
name,
ImmutableSet.of(desugarJdkLibs, ToolHelper.DESUGAR_LIB_CONVERSIONS),
Paths.get("src/library_desugar/" + specificationPath),
- ToolHelper.getAndroidJar(androidJarLevel));
- }
-
- // This can be used to build custom specifications for testing purposes.
- public LibraryDesugaringSpecification(
- String name, Set<Path> desugarJdkLibs, Path specification, Path androidJar) {
- this(name, desugarJdkLibs, specification, ImmutableSet.of(androidJar), "");
+ ImmutableSet.of(ToolHelper.getAndroidJar(androidJarLevel)),
+ "");
}
// This can be used to build custom specifications for testing purposes.
@@ -116,7 +107,8 @@
Paths.get(DESUGARED_LIB_RELEASES_DIR, version, "desugar_jdk_libs.jar"),
Paths.get(DESUGARED_LIB_RELEASES_DIR, version, "desugar_jdk_libs_configuration.jar")),
Paths.get(DESUGARED_LIB_RELEASES_DIR, version, "desugar.json"),
- ToolHelper.getAndroidJar(androidJarLevel));
+ ImmutableSet.of(ToolHelper.getAndroidJar(androidJarLevel)),
+ "");
}
@Override
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDex.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDex.java
new file mode 100644
index 0000000..8c5cdd0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesInDex.java
@@ -0,0 +1,205 @@
+// 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.nestaccesscontrol;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfVm;
+import com.android.tools.r8.desugar.nestaccesscontrol.NestAttributesInDex.Host.Member1;
+import com.android.tools.r8.desugar.nestaccesscontrol.NestAttributesInDex.Host.Member2;
+import com.android.tools.r8.transformers.ClassFileTransformer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+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.Opcodes;
+
+@RunWith(Parameterized.class)
+public class NestAttributesInDex extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+ }
+
+ private static final String EXPECTED_OUTPUT =
+ StringUtils.lines(
+ "true", "true", "true", "true", "true", "true", "true", "true", "true", "false", "false",
+ "true", "true", "true", "false", "false", "true", "true", "true", "false", "false",
+ "true", "true", "true");
+
+ @Test
+ public void testRuntime() throws Exception {
+ assumeTrue(
+ parameters.isCfRuntime()
+ && parameters.asCfRuntime().isNewerThanOrEqual(CfVm.JDK11)
+ && parameters.getApiLevel().isEqualTo(AndroidApiLevel.B));
+ testForJvm()
+ .addProgramClassFileData(getTransformedClasses())
+ .addProgramClasses(OtherHost.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject host = inspector.clazz(Host.class);
+ ClassSubject member1 = inspector.clazz(Member1.class);
+ ClassSubject member2 = inspector.clazz(Member2.class);
+ assertEquals(
+ ImmutableList.of(member1.asTypeSubject(), member2.asTypeSubject()),
+ host.getFinalNestMembersAttribute());
+ assertEquals(host.asTypeSubject(), member1.getFinalNestHostAttribute());
+ assertEquals(host.asTypeSubject(), member2.getFinalNestHostAttribute());
+ ClassSubject otherHost = inspector.clazz(OtherHost.class);
+ assertNull(otherHost.getFinalNestHostAttribute());
+ assertEquals(0, otherHost.getFinalNestMembersAttribute().size());
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ testForD8(parameters.getBackend())
+ .addProgramClassFileData(getTransformedClasses())
+ .addProgramClasses(OtherHost.class)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(
+ options -> {
+ options.emitNestAnnotationsInDex = true;
+ })
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ // No Art versions have support for nest attributes yet.
+ .assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+ }
+
+ public Collection<byte[]> getTransformedClasses() throws Exception {
+ ClassFileTransformer transformer =
+ transformer(TestClass.class)
+ .setMinVersion(CfVm.JDK11)
+ .transformMethodInsnInMethod(
+ "main",
+ ((opcode, owner, name, descriptor, isInterface, continuation) -> {
+ if (owner.equals(DescriptorUtils.getClassBinaryName(AdditionalClassAPIs.class))) {
+ if (name.equals("getNestMembers")) {
+ continuation.visitMethodInsn(
+ Opcodes.INVOKEVIRTUAL,
+ "java/lang/Class",
+ "getNestMembers",
+ "()[Ljava/lang/Class;",
+ false);
+ } else if (name.equals("getNestHost")) {
+ continuation.visitMethodInsn(
+ Opcodes.INVOKEVIRTUAL,
+ "java/lang/Class",
+ "getNestHost",
+ "()Ljava/lang/Class;",
+ false);
+ } else if (name.equals("isNestmateOf")) {
+ continuation.visitMethodInsn(
+ Opcodes.INVOKEVIRTUAL,
+ "java/lang/Class",
+ "isNestmateOf",
+ "(Ljava/lang/Class;)Z",
+ false);
+ } else {
+ fail("Unsupported rewriting of API " + owner + "." + name + descriptor);
+ }
+ } else {
+ continuation.visitMethodInsn(opcode, owner, name, descriptor, isInterface);
+ }
+ }));
+
+ return ImmutableList.of(
+ transformer.transform(),
+ withNest(Host.class).transform(),
+ withNest(Member1.class).transform(),
+ withNest(Member2.class).transform());
+ }
+
+ private ClassFileTransformer withNest(Class<?> clazz) throws Exception {
+ return transformer(clazz).setNest(Host.class, Member1.class, Member2.class);
+ }
+
+ static class AdditionalClassAPIs {
+ public static Class<?>[] getNestMembers(Class<?> clazz) {
+ throw new RuntimeException();
+ }
+
+ public static Class<?> getNestHost(Class<?> clazz) {
+ throw new RuntimeException();
+ }
+
+ public static boolean isNestmateOf(Class<?> class1, Class<?> class2) {
+ throw new RuntimeException();
+ }
+ }
+
+ static class TestClass {
+
+ public static boolean sameArrayContent(Class<?>[] array1, Class<?>[] array2) {
+ Set<Class<?>> expected = new HashSet<>(Arrays.asList(array1));
+ for (Class<?> clazz : array2) {
+ if (!expected.remove(clazz)) {
+ return false;
+ }
+ }
+ return expected.isEmpty();
+ }
+
+ public static void main(String[] args) {
+ Class<?>[] nestMembers = new Class<?>[] {Host.class, Member1.class, Member2.class};
+ System.out.println(
+ sameArrayContent(nestMembers, AdditionalClassAPIs.getNestMembers(Host.class)));
+ System.out.println(
+ sameArrayContent(nestMembers, AdditionalClassAPIs.getNestMembers(Member1.class)));
+ System.out.println(
+ sameArrayContent(nestMembers, AdditionalClassAPIs.getNestMembers(Member2.class)));
+ System.out.println(AdditionalClassAPIs.getNestHost(Host.class).equals(Host.class));
+ System.out.println(AdditionalClassAPIs.getNestHost(Member1.class).equals(Host.class));
+ System.out.println(AdditionalClassAPIs.getNestHost(Member2.class).equals(Host.class));
+ for (Class<?> class1 : nestMembers) {
+ for (Class<?> class2 : nestMembers) {
+ System.out.println(AdditionalClassAPIs.isNestmateOf(class1, class2));
+ }
+ System.out.println(AdditionalClassAPIs.isNestmateOf(OtherHost.class, class1));
+ System.out.println(AdditionalClassAPIs.isNestmateOf(class1, OtherHost.class));
+ }
+ System.out.println(AdditionalClassAPIs.getNestHost(OtherHost.class).equals(OtherHost.class));
+ System.out.println(
+ sameArrayContent(
+ new Class<?>[] {OtherHost.class},
+ AdditionalClassAPIs.getNestMembers(OtherHost.class)));
+ System.out.println(AdditionalClassAPIs.isNestmateOf(OtherHost.class, OtherHost.class));
+ }
+ }
+
+ static class OtherHost {}
+
+ static class Host {
+ static class Member1 {}
+
+ static class Member2 {}
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultMethodInvokeSuperOnDefaultLibraryMethodTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultMethodInvokeSuperOnDefaultLibraryMethodTest.java
new file mode 100644
index 0000000..0cb64c8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/DefaultMethodInvokeSuperOnDefaultLibraryMethodTest.java
@@ -0,0 +1,175 @@
+// 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.desugaring.interfacemethods;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
+import static org.hamcrest.CoreMatchers.allOf;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringDiagnostic;
+import com.android.tools.r8.utils.StringUtils;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.function.Consumer;
+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 DefaultMethodInvokeSuperOnDefaultLibraryMethodTest extends TestBase {
+
+ @Parameter() public TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimes().build();
+ }
+
+ private static final String EXPECTED_OUTPUT = StringUtils.lines("1", "2");
+
+ private boolean runtimeHasConsumerInterface(TestParameters parameters) {
+ // java,util.function.Consumer was introduced at API level 24.
+ return parameters.asDexRuntime().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N);
+ }
+
+ @Test
+ public void testD8WithDefaultInterfaceMethodDesugaringWithAPIInLibrary() throws Exception {
+ testForD8(parameters.getBackend())
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
+ .addInnerClasses(getClass())
+ .setMinApi(AndroidApiLevel.I_MR1)
+ .compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics
+ .assertOnlyWarnings()
+ .assertWarningsMatch(
+ allOf(
+ diagnosticType(StringDiagnostic.class),
+ diagnosticMessage(
+ containsString(
+ "Interface method desugaring has inserted NoSuchMethodError"
+ + " replacing a super call in")),
+ diagnosticMessage(containsString("forEachPrint")))))
+ .run(parameters.getRuntime(), TestClass.class)
+ .applyIf(
+ // If the platform does not have java.util.function.Consumer the lambda instantiation
+ // will throw NoClassDefFoundError as it implements java.util.function.Consumer.
+ // Otherwise, the generated code will throw NoSuchMethodError.
+ runtimeHasConsumerInterface(parameters),
+ b -> b.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
+ b -> b.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
+ }
+
+ @Test
+ public void testD8WithDefaultInterfaceMethodDesugaringWithoutAPIInLibrary() throws Exception {
+ testForD8(parameters.getBackend())
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.M))
+ .addInnerClasses(getClass())
+ .setMinApi(AndroidApiLevel.I_MR1)
+ .compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics
+ .assertOnlyWarnings()
+ .assertWarningsMatch(
+ diagnosticType(InterfaceDesugarMissingTypeDiagnostic.class)))
+ .run(parameters.getRuntime(), TestClass.class)
+ .applyIf(
+ // If the platform does not have java.util.function.Consumer the lambda instantiation
+ // will throw NoClassDefFoundError as it implements java.util.function.Consumer.
+ // Otherwise, the generated code will throw NoSuchMethodError.
+ runtimeHasConsumerInterface(parameters),
+ b -> b.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
+ b -> b.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
+ }
+
+ @Test
+ public void testD8WithDefaultInterfaceMethodSupport() throws Exception {
+ assumeTrue(
+ parameters.asDexRuntime().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N));
+ testForD8(parameters.getBackend())
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
+ .addInnerClasses(getClass())
+ .setMinApi(AndroidApiLevel.N)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ @Test
+ public void testR8WithDefaultInterfaceMethodDesugaringWithAPIInLibrary() throws Exception {
+ testForR8(parameters.getBackend())
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
+ .addInnerClasses(getClass())
+ .setMinApi(AndroidApiLevel.I_MR1)
+ .addKeepMainRule(TestClass.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertFailureWithErrorThatThrows(NoSuchMethodError.class);
+ }
+
+ @Test
+ public void testR8WithDefaultInterfaceMethodDesugaringWithoutAPIInLibrary() throws Exception {
+ testForR8(parameters.getBackend())
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.M))
+ .addInnerClasses(getClass())
+ .setMinApi(AndroidApiLevel.I_MR1)
+ .addKeepMainRule(TestClass.class)
+ .addDontWarn(Consumer.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .applyIf(
+ // If the platform does not have java.util.function.Consumer the lambda instantiation
+ // will throw NoClassDefFoundError as it implements java.util.function.Consumer.
+ // Otherwise, the generated code will throw NoSuchMethodError.
+ runtimeHasConsumerInterface(parameters),
+ b -> b.assertFailureWithErrorThatThrows(NoSuchMethodError.class),
+ b -> b.assertFailureWithErrorThatThrows(NoClassDefFoundError.class));
+ }
+
+ @Test
+ public void testR8WithDefaultInterfaceMethodSupport() throws Exception {
+ assumeTrue(
+ parameters.asDexRuntime().getMinApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N));
+ testForR8(parameters.getBackend())
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.T))
+ .addInnerClasses(getClass())
+ .setMinApi(AndroidApiLevel.N)
+ .addKeepMainRule(TestClass.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ interface IntegerIterable extends Iterable<Integer> {
+ default void forEachPrint() {
+ Iterable.super.forEach(System.out::println);
+ }
+ }
+
+ static class IntegerIterable1And2 implements IntegerIterable {
+
+ @Override
+ public Iterator<Integer> iterator() {
+ List<Integer> result = new ArrayList<>();
+ result.add(1);
+ result.add(2);
+ return result.iterator();
+ }
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ new IntegerIterable1And2().forEachPrint();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java
index fc4fba0..c412e9f 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1620Test.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.L8TestCompileResult;
+import com.android.tools.r8.LibraryDesugaringTestConfiguration;
import com.android.tools.r8.LibraryDesugaringTestConfiguration.PresentKeepRuleConsumer;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestCompileResult;
@@ -119,9 +120,13 @@
.apply(configuration)
.setMinApi(getApiLevel())
.enableCoreLibraryDesugaring(
- getApiLevel(),
- keepRuleConsumer,
- StringResource.fromFile(getDesugaredLibraryConfiguration()))
+ LibraryDesugaringTestConfiguration.builder()
+ .setMinApi(getApiLevel())
+ .setKeepRuleConsumer(keepRuleConsumer)
+ .addDesugaredLibraryConfiguration(
+ StringResource.fromFile(getDesugaredLibraryConfiguration()))
+ .dontAddRunClasspath()
+ .build())
.compile()
.assertAllInfoMessagesMatch(
anyOf(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java
index 71b7da8..53fa602 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineMethodWithRetargetedLibMemberTest.java
@@ -4,16 +4,19 @@
package com.android.tools.r8.ir.optimize.inliner;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.CompilationSpecification.R8_L8DEBUG;
+import static com.android.tools.r8.desugar.desugaredlibrary.test.LibraryDesugaringSpecification.getJdk8Jdk11;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.LibraryDesugaringTestConfiguration;
-import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
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.google.common.collect.ImmutableList;
import java.util.Arrays;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -23,25 +26,31 @@
public class InlineMethodWithRetargetedLibMemberTest extends DesugaredLibraryTestBase {
private final TestParameters parameters;
+ private final LibraryDesugaringSpecification libraryDesugaringSpecification;
+ private final CompilationSpecification compilationSpecification;
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return TestBase.getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ @Parameters(name = "{0}, spec: {1}, {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getJdk8Jdk11(),
+ ImmutableList.of(R8_L8DEBUG));
}
- public InlineMethodWithRetargetedLibMemberTest(TestParameters parameters) {
+ public InlineMethodWithRetargetedLibMemberTest(
+ TestParameters parameters,
+ LibraryDesugaringSpecification libraryDesugaringSpecification,
+ CompilationSpecification compilationSpecification) {
this.parameters = parameters;
+ this.libraryDesugaringSpecification = libraryDesugaringSpecification;
+ this.compilationSpecification = compilationSpecification;
}
@Test
- public void test() throws Exception {
- testForR8(parameters.getBackend())
- .addLibraryFiles(getLibraryFile())
+ public void test() throws Throwable {
+ testForDesugaredLibrary(parameters, libraryDesugaringSpecification, compilationSpecification)
.addProgramClasses(TestClass.class)
.addKeepMainRule(TestClass.class)
- .enableCoreLibraryDesugaring(
- LibraryDesugaringTestConfiguration.forApiLevel(parameters.getApiLevel()))
- .setMinApi(parameters.getApiLevel())
.compile()
.inspect(
inspector ->
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java
index 57b70d2..198fcde 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java
@@ -121,13 +121,13 @@
assertThat(inspector.clazz(LibrarySubclass.class), isPresent());
List<FoundMethodSubject> methods =
inspector.clazz(LibrarySubclass.class).allMethods();
- assertEquals(3, methods.size());
+ assertEquals(4, methods.size());
assertEquals(
1, methods.stream().filter(FoundMethodSubject::isInstanceInitializer).count());
assertEquals(
1, methods.stream().filter(m -> m.getFinalName().contains("main")).count());
assertEquals(
- 1, methods.stream().filter(m -> m.getOriginalName().contains("foo")).count());
+ 2, methods.stream().filter(m -> m.getOriginalName().contains("foo")).count());
});
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
index 61c6fb5..55b84f4 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
@@ -215,6 +215,16 @@
}
@Override
+ public TypeSubject getFinalNestHostAttribute() {
+ throw new Unreachable("Cannot determine NestHost attribute of an absent class");
+ }
+
+ @Override
+ public List<TypeSubject> getFinalNestMembersAttribute() {
+ throw new Unreachable("Cannot determine NestMembers attribute of an absent class");
+ }
+
+ @Override
public KmClassSubject getKmClass() {
return null;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index d604156..36a856e 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -242,6 +242,10 @@
public abstract String getFinalSignatureAttribute();
+ public abstract TypeSubject getFinalNestHostAttribute();
+
+ public abstract List<TypeSubject> getFinalNestMembersAttribute();
+
public abstract KmClassSubject getKmClass();
public abstract KmPackageSubject getKmPackage();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index fbf91d6..5b0e184 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.NestMemberClassAttribute;
import com.android.tools.r8.kotlin.KotlinClassMetadataReader;
import com.android.tools.r8.naming.ClassNamingForNameMapper;
import com.android.tools.r8.naming.MemberNaming;
@@ -486,6 +487,23 @@
}
@Override
+ public TypeSubject getFinalNestHostAttribute() {
+ if (dexClass.getNestHost() == null) {
+ return null;
+ }
+ return new TypeSubject(codeInspector, dexClass.getNestHost());
+ }
+
+ @Override
+ public List<TypeSubject> getFinalNestMembersAttribute() {
+ List<TypeSubject> result = new ArrayList<>();
+ for (NestMemberClassAttribute member : dexClass.getNestMembersClassAttributes()) {
+ result.add(new TypeSubject(codeInspector, member.getNestMember()));
+ }
+ return result;
+ }
+
+ @Override
public int hashCode() {
int result = codeInspector.hashCode();
result = 31 * result + dexClass.hashCode();
diff --git a/tools/create_r8lib.py b/tools/create_r8lib.py
index 6f77ba6..c48eaca 100755
--- a/tools/create_r8lib.py
+++ b/tools/create_r8lib.py
@@ -23,30 +23,35 @@
def parse_options():
parser = argparse.ArgumentParser(description='Tag R8 Versions')
parser.add_argument(
- '--r8jar',
- required=True,
- help='The R8 jar to compile')
+ '--classpath',
+ action='append',
+ help='Dependencies to add to classpath')
parser.add_argument(
- '--output',
- required=True,
- help='The output path for the r8lib')
+ '--debug-agent',
+ action='store_true',
+ default=False,
+ help='Create a socket for debugging')
parser.add_argument(
- '--pg-conf',
- action='append',
- help='Keep configuration')
+ '--excldeps-variant',
+ action='store_true',
+ default=False,
+ help='Mark this artifact as an "excldeps" variant of the compiler')
parser.add_argument(
- '--lib',
- action='append',
- help='Additional libraries (JDK 1.8 rt.jar already included)')
+ '--lib',
+ action='append',
+ help='Additional libraries (JDK 1.8 rt.jar already included)')
parser.add_argument(
- '--classpath',
- action='append',
- help='Dependencies to add to classpath')
+ '--output',
+ required=True,
+ help='The output path for the r8lib')
parser.add_argument(
- '--excldeps-variant',
- action='store_true',
- default=False,
- help='Mark this artifact as an "excldeps" variant of the compiler')
+ '--pg-conf',
+ action='append',
+ help='Keep configuration')
+ parser.add_argument(
+ '--r8jar',
+ required=True,
+ help='The R8 jar to compile')
return parser.parse_args()
def get_r8_version(r8jar):
@@ -82,6 +87,8 @@
source_file_template = 'R8_%MAP_ID_%MAP_HASH'
# TODO(b/139725780): See if we can remove or lower the heap size (-Xmx8g).
cmd = [jdk.GetJavaExecutable(), '-Xmx8g', '-ea']
+ if args.debug_agent:
+ cmd.extend(['-agentlib:jdwp=transport=dt_socket,server=y,suspend=y,address=*:5005'])
cmd.extend(['-cp', 'build/libs/r8_with_deps.jar', 'com.android.tools.r8.R8'])
cmd.append(args.r8jar)
cmd.append('--classfile')