Merge commit '9066ac43ffdd344123a2f1e13979e9df3232b42b' into dev-release
diff --git a/.gitignore b/.gitignore
index 45852a0..2e7f798 100644
--- a/.gitignore
+++ b/.gitignore
@@ -225,6 +225,8 @@
third_party/r8.tar.gz
third_party/r8-releases/2.0.74
third_party/r8-releases/2.0.74.tar.gz
+third_party/r8-releases/3.2.54
+third_party/r8-releases/3.2.54.tar.gz
third_party/r8mappings
third_party/r8mappings.tar.gz
third_party/remapper
diff --git a/build.gradle b/build.gradle
index 67074c7..e5467f0 100644
--- a/build.gradle
+++ b/build.gradle
@@ -354,6 +354,7 @@
"retrace/binary_compatibility",
"r8",
"r8-releases/2.0.74",
+ "r8-releases/3.2.54",
"r8mappings",
"tachiyomi"
],
diff --git a/buildSrc/src/main/java/dx/DexMergerTask.java b/buildSrc/src/main/java/dx/DexMergerTask.java
index 735afa7..5dea52b 100644
--- a/buildSrc/src/main/java/dx/DexMergerTask.java
+++ b/buildSrc/src/main/java/dx/DexMergerTask.java
@@ -10,17 +10,13 @@
import java.util.List;
import java.util.Set;
import javax.inject.Inject;
-import org.gradle.api.Action;
import org.gradle.api.DefaultTask;
-import org.gradle.api.UncheckedIOException;
import org.gradle.api.file.FileCollection;
import org.gradle.api.tasks.InputFile;
import org.gradle.api.tasks.InputFiles;
import org.gradle.api.tasks.OutputFile;
import org.gradle.api.tasks.TaskAction;
-import org.gradle.process.ExecSpec;
import org.gradle.workers.IsolationMode;
-import org.gradle.workers.WorkerConfiguration;
import org.gradle.workers.WorkerExecutor;
import utils.Utils;
@@ -67,19 +63,30 @@
@TaskAction
void exec() {
- workerExecutor.submit(RunDexMerger.class, config -> {
- config.setIsolationMode(IsolationMode.NONE);
- config.params(source.getFiles(), destination, dexMergerExecutable);
- });
+ workerExecutor.submit(
+ RunDexMerger.class,
+ config -> {
+ File executable =
+ dexMergerExecutable.isPresent()
+ ? dexMergerExecutable.get()
+ : config
+ .getForkOptions()
+ .getWorkingDir()
+ .toPath()
+ .resolve(Utils.dexMergerExecutable())
+ .toFile();
+ config.setIsolationMode(IsolationMode.NONE);
+ config.params(source.getFiles(), destination, executable);
+ });
}
public static class RunDexMerger implements Runnable {
private final Set<File> sources;
private final File destination;
- private final Optional<File> dexMergerExecutable;
+ private final File dexMergerExecutable;
@Inject
- public RunDexMerger(Set<File> sources, File destination, Optional<File> dexMergerExecutable) {
+ public RunDexMerger(Set<File> sources, File destination, File dexMergerExecutable) {
this.sources = sources;
this.destination = destination;
this.dexMergerExecutable = dexMergerExecutable;
@@ -89,7 +96,7 @@
public void run() {
try {
List<String> command = new ArrayList<>();
- command.add(dexMergerExecutable.or(Utils::dexMergerExecutable).getCanonicalPath());
+ command.add(dexMergerExecutable.getCanonicalPath());
command.add(destination.getCanonicalPath());
for (File source : sources) {
command.add(source.getCanonicalPath());
diff --git a/buildSrc/src/main/java/dx/DxTask.java b/buildSrc/src/main/java/dx/DxTask.java
index d8975dc..e05e8fb 100644
--- a/buildSrc/src/main/java/dx/DxTask.java
+++ b/buildSrc/src/main/java/dx/DxTask.java
@@ -75,20 +75,31 @@
@TaskAction
void exec() {
- workerExecutor.submit(RunDx.class, config -> {
- config.setIsolationMode(IsolationMode.NONE);
- config.params(source.getFiles(), destination, dxExecutable, debug);
- });
+ workerExecutor.submit(
+ RunDx.class,
+ config -> {
+ File executable =
+ dxExecutable.isPresent()
+ ? dxExecutable.get()
+ : config
+ .getForkOptions()
+ .getWorkingDir()
+ .toPath()
+ .resolve(Utils.dxExecutable())
+ .toFile();
+ config.setIsolationMode(IsolationMode.NONE);
+ config.params(source.getFiles(), destination, executable, debug);
+ });
}
public static class RunDx implements Runnable {
private final Set<File> sources;
private final File destination;
- private final Optional<File> dxExecutable;
+ private final File dxExecutable;
private final boolean debug;
@Inject
- public RunDx(Set<File> sources, File destination, Optional<File> dxExecutable, boolean debug) {
+ public RunDx(Set<File> sources, File destination, File dxExecutable, boolean debug) {
this.sources = sources;
this.destination = destination;
this.dxExecutable = dxExecutable;
@@ -99,7 +110,7 @@
public void run() {
try {
List<String> command = new ArrayList<>();
- command.add(dxExecutable.or(Utils::dxExecutable).getCanonicalPath());
+ command.add(dxExecutable.getCanonicalPath());
command.add("--dex");
command.add("--output");
command.add(destination.getCanonicalPath());
diff --git a/buildSrc/src/main/java/utils/Utils.java b/buildSrc/src/main/java/utils/Utils.java
index 7843edd..7f09b81 100644
--- a/buildSrc/src/main/java/utils/Utils.java
+++ b/buildSrc/src/main/java/utils/Utils.java
@@ -3,7 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package utils;
-import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
public class Utils {
public static String toolsDir() {
@@ -17,13 +18,17 @@
}
}
- public static File dxExecutable() {
- String dxExecutableName = Utils.toolsDir().equals("windows") ? "dx.bat" : "dx";
- return new File("tools/" + Utils.toolsDir() + "/dx/bin/" + dxExecutableName);
+ public static boolean isWindows() {
+ return toolsDir().equals("windows");
}
- public static File dexMergerExecutable() {
- String executableName = Utils.toolsDir().equals("windows") ? "dexmerger.bat" : "dexmerger";
- return new File("tools/" + Utils.toolsDir() + "/dx/bin/" + executableName);
+ public static Path dxExecutable() {
+ String dxExecutableName = isWindows() ? "dx.bat" : "dx";
+ return Paths.get("tools", toolsDir(), "dx", "bin", dxExecutableName);
+ }
+
+ public static Path dexMergerExecutable() {
+ String executableName = isWindows() ? "dexmerger.bat" : "dexmerger";
+ return Paths.get("tools", toolsDir(), "dx", "bin", executableName);
}
}
diff --git a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
index de5d525..57f7c3e 100644
--- a/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
+++ b/src/library_desugar/jdk11/desugar_jdk_libs_alternative_3.json
@@ -55,7 +55,6 @@
"api_level_below_or_equal": 23,
"rewrite_prefix": {
"java.io.DesugarBufferedReader": "j$.io.DesugarBufferedReader",
- "java.io.UncheckedIOException": "j$.io.UncheckedIOException",
"java.util.DoubleSummaryStatistics": "j$.util.DoubleSummaryStatistics",
"java.util.IntSummaryStatistics": "j$.util.IntSummaryStatistics",
"java.util.LongSummaryStatistics": "j$.util.LongSummaryStatistics",
@@ -70,6 +69,9 @@
"java.util.function.": "j$.util.function.",
"java.util.stream.": "j$.util.stream."
},
+ "maintain_prefix": [
+ "java.io.UncheckedIOException"
+ ],
"emulate_interface": {
"java.lang.Iterable": "j$.lang.Iterable",
"java.util.Collection": "j$.util.Collection",
diff --git a/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java b/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java
index 90544cc..b638235 100644
--- a/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java
+++ b/src/main/java/com/android/tools/r8/CompatProguardCommandBuilder.java
@@ -14,9 +14,7 @@
public CompatProguardCommandBuilder(
boolean forceProguardCompatibility, DiagnosticsHandler diagnosticsHandler) {
super(diagnosticsHandler);
- if (forceProguardCompatibility) {
- internalForceProguardCompatibility();
- }
+ setProguardCompatibility(forceProguardCompatibility);
setIgnoreDexInArchive(true);
}
@@ -26,9 +24,7 @@
public CompatProguardCommandBuilder(
boolean forceProguardCompatibility, boolean disableVerticalClassMerging) {
- if (forceProguardCompatibility) {
- internalForceProguardCompatibility();
- }
+ setProguardCompatibility(forceProguardCompatibility);
setDisableVerticalClassMerging(disableVerticalClassMerging);
setIgnoreDexInArchive(true);
}
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index 7f74668..c953853 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -539,7 +539,6 @@
assert !internal.isMinifying();
assert !internal.passthroughDexCode;
internal.passthroughDexCode = true;
- assert internal.neverMergePrefixes.contains("j$.");
// Assert some of R8 optimizations are disabled.
assert !internal.inlinerOptions().enableInlining;
@@ -580,7 +579,9 @@
HorizontalClassMergerOptions horizontalClassMergerOptions =
internal.horizontalClassMergerOptions();
if (internal.isGeneratingDex()) {
- horizontalClassMergerOptions.setRestrictToSynthetics();
+ // TODO(b/227791663): Disable until fixed.
+ horizontalClassMergerOptions.disable();
+ // horizontalClassMergerOptions.setRestrictToSynthetics();
} else {
assert internal.isGeneratingClassFiles();
horizontalClassMergerOptions.disable();
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 05f03d2..f259f26 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -138,10 +138,6 @@
// Internal
- void internalForceProguardCompatibility() {
- this.forceProguardCompatibility = true;
- }
-
void setDisableVerticalClassMerging(boolean disableVerticalClassMerging) {
this.disableVerticalClassMerging = disableVerticalClassMerging;
}
@@ -203,6 +199,23 @@
return self();
}
+ /**
+ * Set Proguard compatibility mode.
+ *
+ * <p>If true, R8 will attempt to retain more compatibility with Proguard. Most notably, R8 will
+ * introduce rules for keeping more default constructors as well as various attributes. Note
+ * that setting R8 in compatibility mode will result in larger residual programs.
+ */
+ public Builder setProguardCompatibility(boolean value) {
+ this.forceProguardCompatibility = value;
+ return self();
+ }
+
+ /** Get the current value of Proguard compatibility mode. */
+ public boolean getProguardCompatibility() {
+ return forceProguardCompatibility;
+ }
+
/** Add proguard configuration-file resources. */
public Builder addProguardConfigurationFiles(Path... paths) {
guard(() -> {
@@ -851,6 +864,11 @@
return enableMinification;
}
+ /** Get the Proguard compatibility state. */
+ public boolean getProguardCompatibility() {
+ return forceProguardCompatibility;
+ }
+
@Override
InternalOptions getInternalOptions() {
InternalOptions internal = new InternalOptions(getMode(), proguardConfiguration, getReporter());
diff --git a/src/main/java/com/android/tools/r8/R8CommandParser.java b/src/main/java/com/android/tools/r8/R8CommandParser.java
index 5e7cf59..56e2b97 100644
--- a/src/main/java/com/android/tools/r8/R8CommandParser.java
+++ b/src/main/java/com/android/tools/r8/R8CommandParser.java
@@ -83,6 +83,7 @@
+ "# Minimum Android API level compatibility, default: "
+ AndroidApiLevel.getDefault().getLevel()
+ ".",
+ " --pg-compat # Compile with R8 in Proguard compatibility mode.",
" --pg-conf <file> # Proguard configuration <file>.",
" --pg-map-output <file> # Output the resulting name and line mapping to"
+ " <file>.",
@@ -195,6 +196,8 @@
"Cannot compile in both --debug and --release mode.", argsOrigin));
}
state.mode = CompilationMode.RELEASE;
+ } else if (arg.equals("--pg-compat")) {
+ builder.setProguardCompatibility(true);
} else if (arg.equals("--dex")) {
if (state.outputMode == OutputMode.ClassFile) {
builder.error(
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index 29dc73f..ce94d5d 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -93,6 +93,12 @@
return opcode == Opcodes.GETSTATIC;
}
+ public boolean isStaticFieldPut() {
+ return opcode == Opcodes.PUTSTATIC;
+ }
+
+ public abstract CfFieldInstruction createWithField(DexField field);
+
@Override
public CfFieldInstruction asFieldInstruction() {
return this;
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 145bc94..2684c0d 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
@@ -22,6 +22,11 @@
}
@Override
+ public CfFieldInstruction createWithField(DexField otherField) {
+ return new CfInstanceFieldRead(otherField);
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerInstanceFieldReadInstruction(this);
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 6d01f49..c9138bb 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
@@ -21,6 +21,11 @@
}
@Override
+ public CfFieldInstruction createWithField(DexField otherField) {
+ return new CfInstanceFieldWrite(otherField);
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerInstanceFieldWrite(getField());
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 66fc48e..30715e1 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
@@ -22,6 +22,11 @@
}
@Override
+ public CfFieldInstruction createWithField(DexField otherField) {
+ return new CfStaticFieldRead(otherField);
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerStaticFieldReadInstruction(this);
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 2cd0f26..24b5e6d 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
@@ -21,6 +21,11 @@
}
@Override
+ public CfFieldInstruction createWithField(DexField otherField) {
+ return new CfStaticFieldWrite(otherField);
+ }
+
+ @Override
void internalRegisterUse(
UseRegistry<?> registry, DexClassAndMethod context, ListIterator<CfInstruction> iterator) {
registry.registerStaticFieldWrite(getField());
diff --git a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
index 3e33ca8..7bfd947 100644
--- a/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
+++ b/src/main/java/com/android/tools/r8/dex/CodeToKeep.java
@@ -25,6 +25,7 @@
static CodeToKeep createCodeToKeep(InternalOptions options, NamingLens namingLens) {
if ((!namingLens.hasPrefixRewritingLogic()
+ && options.machineDesugaredLibrarySpecification.getMaintainType().isEmpty()
&& !options.machineDesugaredLibrarySpecification.hasEmulatedInterfaces())
|| options.isDesugaredLibraryCompilation()
|| options.testing.enableExperimentalDesugaredLibraryKeepRuleGenerator) {
@@ -67,6 +68,7 @@
private boolean shouldKeep(DexType type) {
return namingLens.prefixRewrittenType(type) != null
+ || options.machineDesugaredLibrarySpecification.getMaintainType().contains(type)
|| options.machineDesugaredLibrarySpecification.isCustomConversionRewrittenType(type)
|| options.machineDesugaredLibrarySpecification.isEmulatedInterfaceRewrittenType(type)
// TODO(b/158632510): This should prefix match on DexString.
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 5a2bffc..d26278f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -390,9 +390,13 @@
public static DexAnnotation createAnnotationSynthesizedClass(
SyntheticKind kind, DexItemFactory dexItemFactory) {
+ DexString versionHash =
+ dexItemFactory.createString(dexItemFactory.getSyntheticNaming().getVersionHash());
DexAnnotationElement kindElement =
new DexAnnotationElement(dexItemFactory.kindString, DexValueInt.create(kind.getId()));
- DexAnnotationElement[] elements = new DexAnnotationElement[] {kindElement};
+ DexAnnotationElement versionHashElement =
+ new DexAnnotationElement(dexItemFactory.versionHashString, new DexValueString(versionHash));
+ DexAnnotationElement[] elements = new DexAnnotationElement[] {kindElement, versionHashElement};
return new DexAnnotation(
VISIBILITY_BUILD,
new DexEncodedAnnotation(dexItemFactory.annotationSynthesizedClass, elements));
@@ -413,17 +417,29 @@
return null;
}
int length = annotation.annotation.elements.length;
- if (length != 1) {
+ if (length != 2) {
return null;
}
- assert factory.kindString.isLessThan(factory.valueString);
+ assert factory.kindString.isLessThan(factory.versionHashString);
DexAnnotationElement kindElement = annotation.annotation.elements[0];
+ DexAnnotationElement versionHashElement = annotation.annotation.elements[1];
if (kindElement.name != factory.kindString) {
return null;
}
if (!kindElement.value.isDexValueInt()) {
return null;
}
+ if (versionHashElement.name != factory.versionHashString) {
+ return null;
+ }
+ if (!versionHashElement.value.isDexValueString()) {
+ return null;
+ }
+ String currentVersionHash = synthetics.getNaming().getVersionHash();
+ String syntheticVersionHash = versionHashElement.value.asDexValueString().getValue().toString();
+ if (!currentVersionHash.equals(syntheticVersionHash)) {
+ return null;
+ }
SyntheticKind kind =
synthetics.getNaming().fromId(kindElement.value.asDexValueInt().getValue());
return kind;
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
index 765fef3..aeab5fe 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMethod.java
@@ -6,10 +6,9 @@
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
import com.android.tools.r8.references.MethodReference;
-import java.util.function.Consumer;
public abstract class DexClassAndMethod extends DexClassAndMember<DexEncodedMethod, DexMethod>
- implements LookupTarget {
+ implements LookupMethodTarget {
DexClassAndMethod(DexClass holder, DexEncodedMethod method) {
super(holder, method);
@@ -88,16 +87,6 @@
}
@Override
- public boolean isMethodTarget() {
- return true;
- }
-
- @Override
- public DexClassAndMethod asMethodTarget() {
- return this;
- }
-
- @Override
public boolean isMethod() {
return true;
}
@@ -113,8 +102,7 @@
}
@Override
- public void accept(
- Consumer<DexClassAndMethod> methodConsumer, Consumer<LookupLambdaTarget> lambdaConsumer) {
- methodConsumer.accept(this);
+ public DexClassAndMethod getTarget() {
+ return this;
}
}
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 3e5150c..98dac6d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -338,6 +338,7 @@
public final DexString valueString = createString("value");
public final DexString kindString = createString("kind");
+ public final DexString versionHashString = createString("versionHash");
// Prefix for runtime affecting yet potential class-retained annotations.
public final DexString dalvikAnnotationOptimizationPrefix =
@@ -643,7 +644,7 @@
createStaticallyKnownType("Ldalvik/annotation/SourceDebugExtension;");
public final DexType annotationThrows = createStaticallyKnownType("Ldalvik/annotation/Throws;");
public final DexType annotationSynthesizedClass =
- createStaticallyKnownType("Lcom/android/tools/r8/annotations/SynthesizedClass;");
+ createStaticallyKnownType("Lcom/android/tools/r8/annotations/SynthesizedClassV2;");
public final DexType annotationCovariantReturnType =
createStaticallyKnownType("Ldalvik/annotation/codegen/CovariantReturnType;");
public final DexType annotationCovariantReturnTypes =
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 810874b..2e84b7a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -157,7 +157,8 @@
if (clazz == null) {
return false;
}
- if (clazz.isInterface() && appView.getOpenClosedInterfacesCollection().isMaybeOpen(clazz)) {
+ // TODO(b/214496607): Allow uninstantiated reasoning for closed interfaces.
+ if (clazz.isInterface()) {
return false;
}
return !appView.appInfo().isInstantiatedDirectlyOrIndirectly(clazz);
diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
index 8e5ec1f..4354f06 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -360,9 +360,6 @@
if (InternalOptions.SUPPORTED_CF_VERSION.isLessThan(version)) {
throw new CompilationError("Unsupported class file version: " + version, origin);
}
- if (version.isGreaterThanOrEqualTo(InternalOptions.EXPERIMENTAL_CF_VERSION)) {
- application.options.warningExperimentalClassFileVersion(origin);
- }
this.deprecated = AsmUtils.isDeprecated(access);
accessFlags = ClassAccessFlags.fromCfAccessFlags(cleanAccessFlags(access));
type = application.getTypeFromName(name);
diff --git a/src/main/java/com/android/tools/r8/graph/LookupCompletenessHelper.java b/src/main/java/com/android/tools/r8/graph/LookupCompletenessHelper.java
index 4a99071..504ca65 100644
--- a/src/main/java/com/android/tools/r8/graph/LookupCompletenessHelper.java
+++ b/src/main/java/com/android/tools/r8/graph/LookupCompletenessHelper.java
@@ -38,9 +38,9 @@
}
}
- void checkDexClassAndMethod(DexClassAndMethod classAndMethod) {
- checkClass(classAndMethod.getHolder());
- checkMethod(classAndMethod.getDefinition());
+ void checkDexClassAndMethod(LookupMethodTarget methodTarget) {
+ checkClass(methodTarget.getHolder());
+ checkMethod(methodTarget.getDefinition());
}
LookupResultCollectionState computeCollectionState(
diff --git a/src/main/java/com/android/tools/r8/graph/LookupLambdaTarget.java b/src/main/java/com/android/tools/r8/graph/LookupLambdaTarget.java
index 12eeddc..e1209e9 100644
--- a/src/main/java/com/android/tools/r8/graph/LookupLambdaTarget.java
+++ b/src/main/java/com/android/tools/r8/graph/LookupLambdaTarget.java
@@ -30,7 +30,7 @@
@Override
public void accept(
- Consumer<DexClassAndMethod> methodConsumer, Consumer<LookupLambdaTarget> lambdaConsumer) {
+ Consumer<LookupMethodTarget> methodConsumer, Consumer<LookupLambdaTarget> lambdaConsumer) {
lambdaConsumer.accept(this);
}
diff --git a/src/main/java/com/android/tools/r8/graph/LookupMethodTarget.java b/src/main/java/com/android/tools/r8/graph/LookupMethodTarget.java
new file mode 100644
index 0000000..b7a6aa0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/LookupMethodTarget.java
@@ -0,0 +1,33 @@
+// 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.graph;
+
+import java.util.function.Consumer;
+
+public interface LookupMethodTarget extends LookupTarget {
+
+ @Override
+ default boolean isMethodTarget() {
+ return true;
+ }
+
+ @Override
+ default LookupMethodTarget asMethodTarget() {
+ return this;
+ }
+
+ @Override
+ default void accept(
+ Consumer<LookupMethodTarget> methodConsumer, Consumer<LookupLambdaTarget> lambdaConsumer) {
+ methodConsumer.accept(this);
+ }
+
+ DexClass getHolder();
+
+ DexMethod getReference();
+
+ DexEncodedMethod getDefinition();
+
+ DexClassAndMethod getTarget();
+}
diff --git a/src/main/java/com/android/tools/r8/graph/LookupMethodTargetWithAccessOverride.java b/src/main/java/com/android/tools/r8/graph/LookupMethodTargetWithAccessOverride.java
new file mode 100644
index 0000000..d69c5b3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/LookupMethodTargetWithAccessOverride.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.graph;
+
+public class LookupMethodTargetWithAccessOverride implements LookupMethodTarget {
+
+ private final DexClassAndMethod target;
+ private final DexClassAndMethod accessOverride;
+
+ public LookupMethodTargetWithAccessOverride(
+ DexClassAndMethod target, DexClassAndMethod accessOverride) {
+ this.target = target;
+ this.accessOverride = accessOverride;
+ }
+
+ @Override
+ public DexClassAndMethod getAccessOverride() {
+ return accessOverride;
+ }
+
+ @Override
+ public DexClass getHolder() {
+ return target.getHolder();
+ }
+
+ @Override
+ public DexMethod getReference() {
+ return target.getReference();
+ }
+
+ @Override
+ public DexEncodedMethod getDefinition() {
+ return target.getDefinition();
+ }
+
+ @Override
+ public DexClassAndMethod getTarget() {
+ return target;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/LookupResult.java b/src/main/java/com/android/tools/r8/graph/LookupResult.java
index bc85814..b8bc3c8 100644
--- a/src/main/java/com/android/tools/r8/graph/LookupResult.java
+++ b/src/main/java/com/android/tools/r8/graph/LookupResult.java
@@ -5,10 +5,11 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.graph.LookupResult.LookupResultSuccess.LookupResultCollectionState;
-import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
import java.util.ArrayList;
import java.util.Collections;
+import java.util.IdentityHashMap;
import java.util.List;
+import java.util.Map;
import java.util.function.Consumer;
public abstract class LookupResult {
@@ -34,14 +35,14 @@
}
public abstract void forEach(
- Consumer<? super DexClassAndMethod> onMethodTarget,
+ Consumer<? super LookupMethodTarget> onMethodTarget,
Consumer<? super LookupLambdaTarget> onLambdaTarget);
public abstract void forEachFailureDependency(
Consumer<? super DexEncodedMethod> methodCausingFailureConsumer);
public static LookupResultSuccess createResult(
- DexClassAndMethodSet methodTargets,
+ Map<DexMethod, LookupMethodTarget> methodTargets,
List<LookupLambdaTarget> lambdaTargets,
List<DexEncodedMethod> methodsCausingFailure,
LookupResultCollectionState state) {
@@ -60,18 +61,18 @@
private static final LookupResultSuccess EMPTY_INSTANCE =
new LookupResultSuccess(
- DexClassAndMethodSet.empty(),
+ new IdentityHashMap<>(),
Collections.emptyList(),
Collections.emptyList(),
LookupResultCollectionState.Incomplete);
- private final DexClassAndMethodSet methodTargets;
+ private final Map<DexMethod, LookupMethodTarget> methodTargets;
private final List<LookupLambdaTarget> lambdaTargets;
private final List<DexEncodedMethod> methodsCausingFailure;
private LookupResultCollectionState state;
private LookupResultSuccess(
- DexClassAndMethodSet methodTargets,
+ Map<DexMethod, LookupMethodTarget> methodTargets,
List<LookupLambdaTarget> lambdaTargets,
List<DexEncodedMethod> methodsCausingFailure,
LookupResultCollectionState state) {
@@ -99,9 +100,9 @@
@Override
public void forEach(
- Consumer<? super DexClassAndMethod> onMethodTarget,
+ Consumer<? super LookupMethodTarget> onMethodTarget,
Consumer<? super LookupLambdaTarget> onLambdaTarget) {
- methodTargets.forEach(onMethodTarget);
+ methodTargets.forEach((key, value) -> onMethodTarget.accept(value));
lambdaTargets.forEach(onLambdaTarget);
}
@@ -113,7 +114,7 @@
public boolean contains(DexEncodedMethod method) {
// Containment of a method in the lookup results only pertains to the method targets.
- return methodTargets.contains(method);
+ return methodTargets.containsKey(method.getReference());
}
@Override
@@ -145,7 +146,7 @@
}
// TODO(b/150932978): Check lambda targets implementation methods.
if (methodTargets.size() == 1) {
- return methodTargets.iterator().next();
+ return methodTargets.values().iterator().next();
} else if (lambdaTargets.size() == 1) {
return lambdaTargets.get(0);
}
@@ -159,13 +160,14 @@
public static class Builder {
- private final DexClassAndMethodSet methodTargets = DexClassAndMethodSet.create();
+ private final Map<DexMethod, LookupMethodTarget> methodTargets = new IdentityHashMap<>();
private final List<LookupLambdaTarget> lambdaTargets = new ArrayList<>();
private final List<DexEncodedMethod> methodsCausingFailure = new ArrayList<>();
private LookupResultCollectionState state;
- public Builder addMethodTarget(DexClassAndMethod methodTarget) {
- methodTargets.add(methodTarget);
+ public Builder addMethodTarget(LookupMethodTarget methodTarget) {
+ assert methodTarget.isMethodTarget();
+ methodTargets.putIfAbsent(methodTarget.asMethodTarget().getReference(), methodTarget);
return this;
}
@@ -210,7 +212,7 @@
@Override
public void forEach(
- Consumer<? super DexClassAndMethod> onMethodTarget,
+ Consumer<? super LookupMethodTarget> onMethodTarget,
Consumer<? super LookupLambdaTarget> onLambdaTarget) {
// Nothing to iterate for a failed lookup.
}
diff --git a/src/main/java/com/android/tools/r8/graph/LookupTarget.java b/src/main/java/com/android/tools/r8/graph/LookupTarget.java
index cc0d574..4530c0f 100644
--- a/src/main/java/com/android/tools/r8/graph/LookupTarget.java
+++ b/src/main/java/com/android/tools/r8/graph/LookupTarget.java
@@ -14,7 +14,7 @@
return false;
}
- default DexClassAndMethod asMethodTarget() {
+ default LookupMethodTarget asMethodTarget() {
return null;
}
@@ -22,6 +22,10 @@
return null;
}
+ default DexClassAndMethod getAccessOverride() {
+ return null;
+ }
+
void accept(
- Consumer<DexClassAndMethod> methodConsumer, Consumer<LookupLambdaTarget> lambdaConsumer);
+ Consumer<LookupMethodTarget> methodConsumer, Consumer<LookupLambdaTarget> lambdaConsumer);
}
diff --git a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
index 113c31c..49860a7 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodResolutionResult.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.OptionalBool;
-import com.android.tools.r8.utils.collections.DexClassAndMethodSet;
import java.util.Collection;
import java.util.Collections;
import java.util.function.BiPredicate;
@@ -152,7 +151,7 @@
public abstract LookupTarget lookupVirtualDispatchTarget(
InstantiatedObject instance, AppInfoWithClassHierarchy appInfo);
- public abstract DexClassAndMethod lookupVirtualDispatchTarget(
+ public abstract LookupMethodTarget lookupVirtualDispatchTarget(
DexClass dynamicInstance, AppInfoWithClassHierarchy appInfo);
public abstract LookupTarget lookupVirtualDispatchTarget(
@@ -451,8 +450,9 @@
// Only include if the target has code or is native.
boolean isIncomplete =
pinnedPredicate.isPinned(resolvedHolder) && pinnedPredicate.isPinned(resolvedMethod);
+ DexClassAndMethod resolutionPair = getResolutionPair();
return LookupResult.createResult(
- DexClassAndMethodSet.create(getResolutionPair()),
+ Collections.singletonMap(resolutionPair.getReference(), resolutionPair),
Collections.emptyList(),
Collections.emptyList(),
isIncomplete
@@ -466,13 +466,12 @@
initialResolutionHolder.type,
subClass -> {
incompleteness.checkClass(subClass);
- DexClassAndMethod dexClassAndMethod =
+ LookupMethodTarget lookupTarget =
lookupVirtualDispatchTarget(
subClass, appInfo, resolvedHolder.type, resultBuilder::addMethodCausingFailure);
- if (dexClassAndMethod != null) {
- incompleteness.checkDexClassAndMethod(dexClassAndMethod);
- addVirtualDispatchTarget(
- dexClassAndMethod, resolvedHolder.isInterface(), resultBuilder);
+ if (lookupTarget != null) {
+ incompleteness.checkDexClassAndMethod(lookupTarget);
+ addVirtualDispatchTarget(lookupTarget, resolvedHolder.isInterface(), resultBuilder);
}
},
lambda -> {
@@ -552,10 +551,11 @@
}
private static void addVirtualDispatchTarget(
- DexClassAndMethod target,
+ LookupMethodTarget target,
boolean holderIsInterface,
LookupResultSuccess.Builder resultBuilder) {
- DexEncodedMethod targetMethod = target.getDefinition();
+ assert target.isMethodTarget();
+ DexEncodedMethod targetMethod = target.asMethodTarget().getDefinition();
assert !targetMethod.isPrivateMethod();
if (holderIsInterface) {
// Add default interface methods to the list of targets.
@@ -609,7 +609,7 @@
}
@Override
- public DexClassAndMethod lookupVirtualDispatchTarget(
+ public LookupMethodTarget lookupVirtualDispatchTarget(
DexClass dynamicInstance, AppInfoWithClassHierarchy appInfo) {
return lookupVirtualDispatchTarget(
dynamicInstance, appInfo, initialResolutionHolder.type, emptyConsumer());
@@ -634,7 +634,7 @@
lambdaInstance, appInfo, methodCausingFailureConsumer);
}
- private DexClassAndMethod lookupVirtualDispatchTarget(
+ private LookupMethodTarget lookupVirtualDispatchTarget(
DexClass dynamicInstance,
AppInfoWithClassHierarchy appInfo,
DexType resolutionHolder,
@@ -644,18 +644,20 @@
// TODO(b/148591377): Enable this assertion.
// The dynamic type cannot be an interface.
// assert !dynamicInstance.isInterface();
+ DexClassAndMethod initialResolutionPair = getResolutionPair();
if (resolvedMethod.isPrivateMethod()) {
// If the resolved reference is private there is no dispatch.
// This is assuming that the method is accessible, which implies self/nest access.
- return getResolutionPair();
+ return initialResolutionPair;
}
boolean allowPackageBlocked = resolvedMethod.accessFlags.isPackagePrivate();
DexClass current = dynamicInstance;
- DexEncodedMethod overrideTarget = resolvedMethod;
+ DexClassAndMethod overrideTarget = initialResolutionPair;
while (current != null) {
- DexEncodedMethod candidate = lookupOverrideCandidate(overrideTarget, current);
+ DexEncodedMethod candidate =
+ lookupOverrideCandidate(overrideTarget.getDefinition(), current);
if (candidate == DexEncodedMethod.SENTINEL && allowPackageBlocked) {
- overrideTarget = findWideningOverride(resolvedMethod, current, appInfo);
+ overrideTarget = findWideningOverride(initialResolutionPair, current, appInfo);
allowPackageBlocked = false;
continue;
}
@@ -667,7 +669,10 @@
current = current.superType == null ? null : appInfo.definitionFor(current.superType);
continue;
}
- return DexClassAndMethod.create(current, candidate);
+ DexClassAndMethod target = DexClassAndMethod.create(current, candidate);
+ return overrideTarget != initialResolutionPair
+ ? new LookupMethodTargetWithAccessOverride(target, overrideTarget)
+ : target;
}
// If we have not found a candidate and the holder is not an interface it must be because the
// class is missing.
@@ -732,10 +737,10 @@
return null;
}
- private static DexEncodedMethod findWideningOverride(
- DexEncodedMethod resolvedMethod, DexClass clazz, AppInfoWithClassHierarchy appView) {
+ private static DexClassAndMethod findWideningOverride(
+ DexClassAndMethod resolvedMethod, DexClass clazz, AppInfoWithClassHierarchy appView) {
// Otherwise, lookup to first override that is distinct from resolvedMethod.
- assert resolvedMethod.accessFlags.isPackagePrivate();
+ assert resolvedMethod.getDefinition().accessFlags.isPackagePrivate();
while (clazz.superType != null) {
clazz = appView.definitionFor(clazz.superType);
if (clazz == null) {
@@ -743,10 +748,10 @@
}
DexEncodedMethod otherOverride = clazz.lookupVirtualMethod(resolvedMethod.getReference());
if (otherOverride != null
- && isOverriding(resolvedMethod, otherOverride)
+ && isOverriding(resolvedMethod.getDefinition(), otherOverride)
&& (otherOverride.accessFlags.isPublic() || otherOverride.accessFlags.isProtected())) {
- assert resolvedMethod != otherOverride;
- return otherOverride;
+ assert resolvedMethod.getDefinition() != otherOverride;
+ return DexClassAndMethod.create(clazz, otherOverride);
}
}
return resolvedMethod;
@@ -818,19 +823,19 @@
}
@Override
- public DexClassAndMethod lookupVirtualDispatchTarget(
+ public LookupTarget lookupVirtualDispatchTarget(
InstantiatedObject instance, AppInfoWithClassHierarchy appInfo) {
return null;
}
@Override
- public DexClassAndMethod lookupVirtualDispatchTarget(
+ public LookupMethodTarget lookupVirtualDispatchTarget(
DexClass dynamicInstance, AppInfoWithClassHierarchy appInfo) {
return null;
}
@Override
- public DexClassAndMethod lookupVirtualDispatchTarget(
+ public LookupTarget lookupVirtualDispatchTarget(
LambdaDescriptor lambdaInstance,
AppInfoWithClassHierarchy appInfo,
Consumer<? super DexEncodedMethod> methodCausingFailureConsumer) {
@@ -1032,4 +1037,5 @@
return invalidSymbolicReference.get();
}
}
+
}
diff --git a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
index 1321169..aebbc12 100644
--- a/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
+++ b/src/main/java/com/android/tools/r8/graph/analysis/ApiModelAnalysis.java
@@ -73,7 +73,7 @@
public void notifyMarkVirtualDispatchTargetAsLive(
LookupTarget target, EnqueuerWorklist worklist) {
target.accept(
- this::computeAndSetApiLevelForDefinition,
+ lookupMethodTarget -> computeAndSetApiLevelForDefinition(lookupMethodTarget.getTarget()),
lookupLambdaTarget -> {
// The implementation method will be assigned an api level when visited.
});
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
index 1d259f6..4e77680 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMethod.java
@@ -170,7 +170,8 @@
}
ProgramMethodSet result = ProgramMethodSet.create();
lookupResult.forEach(
- methodTarget -> {
+ target -> {
+ DexClassAndMethod methodTarget = target.getTarget();
if (methodTarget.isProgramMethod()) {
result.add(methodTarget.asProgramMethod());
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index acadf11..9ccaec9 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -83,7 +83,6 @@
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagator;
import com.android.tools.r8.optimize.argumentpropagation.ArgumentPropagatorIROptimizer;
import com.android.tools.r8.optimize.interfaces.analysis.OpenClosedInterfacesAnalysis;
-import com.android.tools.r8.optimize.interfaces.analysis.OpenClosedInterfacesAnalysisImpl;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.KeepMethodInfo;
@@ -93,6 +92,7 @@
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.InternalOptions.NeverMergeGroup;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
@@ -107,7 +107,6 @@
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.stream.Collectors;
public class IRConverter {
@@ -158,7 +157,7 @@
private List<Action> onWaveDoneActions = null;
private final Set<DexMethod> prunedMethodsInWave = Sets.newIdentityHashSet();
- private final List<DexString> neverMergePrefixes;
+ private final NeverMergeGroup<DexString> neverMerge;
// Use AtomicBoolean to satisfy TSAN checking (see b/153714743).
AtomicBoolean seenNotNeverMergePrefix = new AtomicBoolean();
AtomicBoolean seenNeverMergePrefix = new AtomicBoolean();
@@ -184,11 +183,11 @@
this.deadCodeRemover = new DeadCodeRemover(appView, codeRewriter);
this.assertionsRewriter = new AssertionsRewriter(appView);
this.idempotentFunctionCallCanonicalizer = new IdempotentFunctionCallCanonicalizer(appView);
- this.neverMergePrefixes =
- options.neverMergePrefixes.stream()
- .map(prefix -> "L" + DescriptorUtils.getPackageBinaryNameFromJavaType(prefix))
- .map(options.itemFactory::createString)
- .collect(Collectors.toList());
+ this.neverMerge =
+ options.neverMerge.map(
+ prefix ->
+ options.itemFactory.createString(
+ "L" + DescriptorUtils.getPackageBinaryNameFromJavaType(prefix)));
if (options.isDesugaredLibraryCompilation()) {
// Specific L8 Settings, performs all desugaring including L8 specific desugaring.
//
@@ -259,7 +258,8 @@
this.memberValuePropagation = new MemberValuePropagation(appViewWithLiveness);
this.methodOptimizationInfoCollector =
new MethodOptimizationInfoCollector(appViewWithLiveness, this);
- this.openClosedInterfacesAnalysis = new OpenClosedInterfacesAnalysisImpl(appViewWithLiveness);
+ // TODO(b/214496607): Enable open/closed interfaces analysis.
+ this.openClosedInterfacesAnalysis = OpenClosedInterfacesAnalysis.empty();
if (options.isMinifying()) {
this.identifierNameStringMarker = new IdentifierNameStringMarker(appViewWithLiveness);
} else {
@@ -550,11 +550,17 @@
if (!appView.options().enableNeverMergePrefixes) {
return;
}
- for (DexString neverMergePrefix : neverMergePrefixes) {
- if (method.getHolderType().descriptor.startsWith(neverMergePrefix)) {
+ DexString descriptor = method.getHolderType().descriptor;
+ for (DexString neverMergePrefix : neverMerge.getPrefixes()) {
+ if (descriptor.startsWith(neverMergePrefix)) {
seenNeverMergePrefix.getAndSet(true);
} else {
- seenNotNeverMergePrefix.getAndSet(true);
+ for (DexString exceptionPrefix : neverMerge.getExceptionPrefixes()) {
+ if (!descriptor.startsWith(exceptionPrefix)) {
+ seenNotNeverMergePrefix.getAndSet(true);
+ break;
+ }
+ }
}
// Don't mix.
// TODO(b/168001352): Consider requiring that no 'never merge' prefix is ever seen as a
@@ -562,16 +568,37 @@
if (seenNeverMergePrefix.get() && seenNotNeverMergePrefix.get()) {
StringBuilder message = new StringBuilder();
message
- .append("Merging dex file containing classes with prefix")
- .append(neverMergePrefixes.size() > 1 ? "es " : " ");
- for (int i = 0; i < neverMergePrefixes.size(); i++) {
+ .append("Merging DEX file containing classes with prefix")
+ .append(neverMerge.getPrefixes().size() > 1 ? "es " : " ");
+ for (int i = 0; i < neverMerge.getPrefixes().size(); i++) {
message
.append("'")
- .append(neverMergePrefixes.get(0).toString().substring(1).replace('/', '.'))
+ .append(neverMerge.getPrefixes().get(i).toString().substring(1).replace('/', '.'))
.append("'")
- .append(i < neverMergePrefixes.size() - 1 ? ", " : "");
+ .append(i < neverMerge.getPrefixes().size() - 1 ? ", " : "");
}
- message.append(" with classes with any other prefixes is not allowed: ");
+ if (!neverMerge.getExceptionPrefixes().isEmpty()) {
+ message
+ .append(" with other classes, except classes with prefix")
+ .append(neverMerge.getExceptionPrefixes().size() > 1 ? "es " : " ");
+ for (int i = 0; i < neverMerge.getExceptionPrefixes().size(); i++) {
+ message
+ .append("'")
+ .append(
+ neverMerge
+ .getExceptionPrefixes()
+ .get(i)
+ .toString()
+ .substring(1)
+ .replace('/', '.'))
+ .append("'")
+ .append(i < neverMerge.getExceptionPrefixes().size() - 1 ? ", " : "");
+ }
+ message.append(",");
+ } else {
+ message.append(" with classes with any other prefixes");
+ }
+ message.append(" is not allowed: ");
boolean first = true;
int limit = 11;
for (DexProgramClass clazz : appView.appInfo().classesWithDeterministicOrder()) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/InvokeExtractor.java b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/InvokeExtractor.java
index 4b15bbc..edd4f14 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/callgraph/InvokeExtractor.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/callgraph/InvokeExtractor.java
@@ -124,7 +124,8 @@
lookupResult
.asLookupResultSuccess()
.forEach(
- methodTarget -> {
+ lookupMethodTarget -> {
+ DexClassAndMethod methodTarget = lookupMethodTarget.getTarget();
if (methodTarget.isProgramMethod()) {
targets.add(methodTarget.asProgramMethod());
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java
index c943028..92bd91e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/DesugaredLibraryAmender.java
@@ -8,8 +8,13 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexDefinitionSupplier;
+import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexLibraryClass;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.utils.Reporter;
import java.util.Map;
@@ -28,20 +33,23 @@
public static void run(AppView<?> appView) {
run(
appView.options().machineDesugaredLibrarySpecification.getAmendLibraryMethods(),
+ appView.options().machineDesugaredLibrarySpecification.getAmendLibraryFields(),
appView,
appView.options().reporter,
appView.computedMinApiLevel());
}
public static void run(
- Map<DexMethod, MethodAccessFlags> amendLibrary,
+ Map<DexMethod, MethodAccessFlags> amendLibraryMethod,
+ Map<DexField, FieldAccessFlags> amendLibraryField,
DexDefinitionSupplier definitions,
Reporter reporter,
ComputedApiLevel minAPILevel) {
- if (amendLibrary.isEmpty()) {
+ if (amendLibraryMethod.isEmpty() && amendLibraryField.isEmpty()) {
return;
}
- new DesugaredLibraryAmender(definitions, reporter, minAPILevel).run(amendLibrary);
+ new DesugaredLibraryAmender(definitions, reporter, minAPILevel)
+ .run(amendLibraryMethod, amendLibraryField);
}
private DesugaredLibraryAmender(
@@ -51,22 +59,40 @@
this.minAPILevel = minAPILevel;
}
- private void run(Map<DexMethod, MethodAccessFlags> amendLibrary) {
- amendLibrary.forEach(this::amendLibraryMethod);
+ private void run(
+ Map<DexMethod, MethodAccessFlags> amendLibraryMethod,
+ Map<DexField, FieldAccessFlags> amendLibraryField) {
+ amendLibraryMethod.forEach(this::amendLibraryMethod);
+ amendLibraryField.forEach(this::amendLibraryField);
+ }
+
+ private void amendLibraryField(DexField field, FieldAccessFlags fieldAccessFlags) {
+ DexLibraryClass libClass = getLibraryClass(field);
+ if (libClass == null) {
+ return;
+ }
+ if (libClass.lookupField(field) != null) {
+ return;
+ }
+ DexEncodedField encodedField =
+ DexEncodedField.syntheticBuilder()
+ .setField(field)
+ .setAccessFlags(fieldAccessFlags)
+ .setApiLevel(minAPILevel)
+ .build();
+ if (fieldAccessFlags.isStatic()) {
+ libClass.appendStaticField(encodedField);
+ } else {
+ libClass.appendInstanceField(encodedField);
+ }
}
private void amendLibraryMethod(DexMethod method, MethodAccessFlags methodAccessFlags) {
- DexClass dexClass = definitions.contextIndependentDefinitionFor(method.getHolderType());
- if (dexClass == null || !dexClass.isLibraryClass()) {
- // Consider just throwing an error.
- reporter.warning(
- "Desugared library: Cannot amend library method "
- + method
- + " because the holder is not a library class"
- + (dexClass == null ? "(null)." : "."));
+ DexLibraryClass libClass = getLibraryClass(method);
+ if (libClass == null) {
return;
}
- if (dexClass.lookupMethod(method) != null) {
+ if (libClass.lookupMethod(method) != null) {
return;
}
DexEncodedMethod encodedMethod =
@@ -76,6 +102,20 @@
.setCode(null)
.setApiLevelForDefinition(minAPILevel)
.build();
- dexClass.getMethodCollection().addMethod(encodedMethod);
+ libClass.getMethodCollection().addMethod(encodedMethod);
+ }
+
+ private DexLibraryClass getLibraryClass(DexReference reference) {
+ DexClass dexClass = definitions.contextIndependentDefinitionFor(reference.getContextType());
+ if (dexClass == null || !dexClass.isLibraryClass()) {
+ // Consider just throwing an error.
+ reporter.warning(
+ "Desugared library: Cannot amend library reference "
+ + reference
+ + " because the holder is not a library class"
+ + (dexClass == null ? "(null)." : "."));
+ return null;
+ }
+ return dexClass.asLibraryClass();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/AbstractMethodParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/AbstractMethodParser.java
deleted file mode 100644
index d63efb6..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/AbstractMethodParser.java
+++ /dev/null
@@ -1,81 +0,0 @@
-// 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.desugar.desugaredlibrary.humanspecification;
-
-import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexString;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.google.common.collect.ImmutableMap;
-import java.util.Map;
-
-/** Parse methods of the form: modifiers* returnType holder#name(arg0, ..., argN) */
-public abstract class AbstractMethodParser {
-
- private static final String SEPARATORS = "\\s+|,\\s+|#|\\(|\\)";
-
- private static final Map<String, Integer> modifiers =
- ImmutableMap.<String, Integer>builder()
- .put("public", Constants.ACC_PUBLIC)
- .put("private", Constants.ACC_PRIVATE)
- .put("protected", Constants.ACC_PROTECTED)
- .put("final", Constants.ACC_FINAL)
- .put("abstract", Constants.ACC_ABSTRACT)
- .put("static", Constants.ACC_STATIC)
- .build();
-
- final DexItemFactory factory;
-
- protected AbstractMethodParser(DexItemFactory factory) {
- this.factory = factory;
- }
-
- // TODO(b/218755060): It would be nice to avoid the split regexp and use a nextToken()
- // method instead, then add a TraversalContinuation.
- public void parseMethod(String signature) {
- String[] tokens = signature.split(SEPARATORS);
- if (tokens.length < 3) {
- throw new CompilationError("Desugared library: cannot parse method " + signature);
- }
- methodStart();
- int first = parseModifiers(tokens);
- returnType(stringTypeToDexType(tokens[first]));
- holderType(stringTypeToDexType(tokens[first + 1]));
- methodName(factory.createString(tokens[first + 1 + 1]));
- for (int i = first + 3; i < tokens.length; i++) {
- argType(stringTypeToDexType(tokens[i]));
- }
- methodEnd();
- }
-
- private DexType stringTypeToDexType(String stringType) {
- return factory.createType(DescriptorUtils.javaTypeToDescriptor(stringType));
- }
-
- private int parseModifiers(String[] split) {
- int index = 0;
- while (modifiers.containsKey(split[index])) {
- modifier(modifiers.get(split[index]));
- index++;
- }
- return index;
- }
-
- protected abstract void methodStart();
-
- protected abstract void methodEnd();
-
- protected abstract void returnType(DexType type);
-
- protected abstract void argType(DexType type);
-
- protected abstract void modifier(int access);
-
- protected abstract void holderType(DexType type);
-
- protected abstract void methodName(DexString name);
-}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
index 2eb550b..5936d8c 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanDesugaredLibrarySpecificationParser.java
@@ -8,10 +8,13 @@
import static com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecificationParser.isHumanSpecification;
import com.android.tools.r8.StringResource;
+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.ir.desugar.desugaredlibrary.TopLevelFlagsBuilder;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.memberparser.HumanFieldParser;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.memberparser.HumanMethodParser;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -48,6 +51,8 @@
static final String WRAPPER_CONVERSION_EXCLUDING_KEY = "wrapper_conversion_excluding";
static final String CUSTOM_CONVERSION_KEY = "custom_conversion";
static final String REWRITE_PREFIX_KEY = "rewrite_prefix";
+ static final String MAINTAIN_PREFIX_KEY = "maintain_prefix";
+ static final String RETARGET_STATIC_FIELD_KEY = "retarget_static_field";
static final String RETARGET_METHOD_KEY = "retarget_method";
static final String RETARGET_METHOD_EMULATED_DISPATCH_KEY =
"retarget_method_with_emulated_dispatch";
@@ -57,11 +62,13 @@
static final String DONT_RETARGET_KEY = "dont_retarget";
static final String BACKPORT_KEY = "backport";
static final String AMEND_LIBRARY_METHOD_KEY = "amend_library_method";
+ static final String AMEND_LIBRARY_FIELD_KEY = "amend_library_field";
static final String SHRINKER_CONFIG_KEY = "shrinker_config";
static final String SUPPORT_ALL_CALLBACKS_FROM_LIBRARY_KEY = "support_all_callbacks_from_library";
private final DexItemFactory dexItemFactory;
private final HumanMethodParser methodParser;
+ private final HumanFieldParser fieldParser;
private final Reporter reporter;
private final boolean libraryCompilation;
private final int minAPILevel;
@@ -76,6 +83,7 @@
int minAPILevel) {
this.dexItemFactory = dexItemFactory;
this.methodParser = new HumanMethodParser(dexItemFactory);
+ this.fieldParser = new HumanFieldParser(dexItemFactory);
this.reporter = reporter;
this.minAPILevel = minAPILevel;
this.libraryCompilation = libraryCompilation;
@@ -235,6 +243,11 @@
builder.putRewritePrefix(rewritePrefix.getKey(), rewritePrefix.getValue().getAsString());
}
}
+ if (jsonFlagSet.has(MAINTAIN_PREFIX_KEY)) {
+ for (JsonElement maintainPrefix : jsonFlagSet.get(MAINTAIN_PREFIX_KEY).getAsJsonArray()) {
+ builder.putMaintainPrefix(maintainPrefix.getAsString());
+ }
+ }
if (jsonFlagSet.has(REWRITE_DERIVED_PREFIX_KEY)) {
for (Map.Entry<String, JsonElement> prefixToMatch :
jsonFlagSet.get(REWRITE_DERIVED_PREFIX_KEY).getAsJsonObject().entrySet()) {
@@ -245,6 +258,14 @@
}
}
}
+ if (jsonFlagSet.has(RETARGET_STATIC_FIELD_KEY)) {
+ for (Map.Entry<String, JsonElement> retarget :
+ jsonFlagSet.get(RETARGET_STATIC_FIELD_KEY).getAsJsonObject().entrySet()) {
+ builder.retargetStaticField(
+ parseField(retarget.getKey()),
+ stringDescriptorToDexType(retarget.getValue().getAsString()));
+ }
+ }
if (jsonFlagSet.has(RETARGET_METHOD_KEY)) {
for (Map.Entry<String, JsonElement> retarget :
jsonFlagSet.get(RETARGET_METHOD_KEY).getAsJsonObject().entrySet()) {
@@ -317,6 +338,13 @@
builder.amendLibraryMethod(methodParser.getMethod(), methodParser.getFlags());
}
}
+ if (jsonFlagSet.has(AMEND_LIBRARY_FIELD_KEY)) {
+ JsonArray amendLibraryMember = jsonFlagSet.get(AMEND_LIBRARY_FIELD_KEY).getAsJsonArray();
+ for (JsonElement amend : amendLibraryMember) {
+ fieldParser.parseField(amend.getAsString());
+ builder.amendLibraryField(fieldParser.getField(), fieldParser.getFlags());
+ }
+ }
}
private Set<DexMethod> parseMethods(JsonArray array) {
@@ -332,6 +360,11 @@
return methodParser.getMethod();
}
+ private DexField parseField(String signature) {
+ fieldParser.parseField(signature);
+ return fieldParser.getField();
+ }
+
private DexType stringDescriptorToDexType(String stringClass) {
return dexItemFactory.createType(DescriptorUtils.javaTypeToDescriptor(stringClass));
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
index 9eb3ed7..b0c7920 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanRewritingFlags.java
@@ -4,8 +4,10 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.Reporter;
@@ -24,8 +26,10 @@
public class HumanRewritingFlags {
private final Map<String, String> rewritePrefix;
+ private final Set<String> maintainPrefix;
private final Map<String, Map<String, String>> rewriteDerivedPrefix;
private final Map<DexType, DexType> emulatedInterfaces;
+ private final Map<DexField, DexType> retargetStaticField;
private final Map<DexMethod, DexType> retargetMethod;
private final Map<DexMethod, DexType> retargetMethodEmulatedDispatch;
private final Map<DexType, DexType> legacyBackport;
@@ -34,11 +38,14 @@
private final Set<DexType> dontRetarget;
private final Map<DexType, Set<DexMethod>> wrapperConversions;
private final Map<DexMethod, MethodAccessFlags> amendLibraryMethod;
+ private final Map<DexField, FieldAccessFlags> amendLibraryField;
HumanRewritingFlags(
Map<String, String> rewritePrefix,
+ Set<String> maintainPrefix,
Map<String, Map<String, String>> rewriteDerivedPrefix,
Map<DexType, DexType> emulateLibraryInterface,
+ Map<DexField, DexType> retargetStaticField,
Map<DexMethod, DexType> retargetMethod,
Map<DexMethod, DexType> retargetMethodEmulatedDispatch,
Map<DexType, DexType> legacyBackport,
@@ -46,10 +53,13 @@
Set<DexMethod> dontRewriteInvocation,
Set<DexType> dontRetarget,
Map<DexType, Set<DexMethod>> wrapperConversion,
- Map<DexMethod, MethodAccessFlags> amendLibraryMethod) {
+ Map<DexMethod, MethodAccessFlags> amendLibraryMethod,
+ Map<DexField, FieldAccessFlags> amendLibraryField) {
this.rewritePrefix = rewritePrefix;
+ this.maintainPrefix = maintainPrefix;
this.rewriteDerivedPrefix = rewriteDerivedPrefix;
this.emulatedInterfaces = emulateLibraryInterface;
+ this.retargetStaticField = retargetStaticField;
this.retargetMethod = retargetMethod;
this.retargetMethodEmulatedDispatch = retargetMethodEmulatedDispatch;
this.legacyBackport = legacyBackport;
@@ -58,11 +68,14 @@
this.dontRetarget = dontRetarget;
this.wrapperConversions = wrapperConversion;
this.amendLibraryMethod = amendLibraryMethod;
+ this.amendLibraryField = amendLibraryField;
}
public static HumanRewritingFlags empty() {
return new HumanRewritingFlags(
ImmutableMap.of(),
+ ImmutableSet.of(),
+ ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
ImmutableMap.of(),
@@ -72,6 +85,7 @@
ImmutableSet.of(),
ImmutableSet.of(),
ImmutableMap.of(),
+ ImmutableMap.of(),
ImmutableMap.of());
}
@@ -84,8 +98,10 @@
reporter,
origin,
rewritePrefix,
+ maintainPrefix,
rewriteDerivedPrefix,
emulatedInterfaces,
+ retargetStaticField,
retargetMethod,
retargetMethodEmulatedDispatch,
legacyBackport,
@@ -93,13 +109,18 @@
dontRewriteInvocation,
dontRetarget,
wrapperConversions,
- amendLibraryMethod);
+ amendLibraryMethod,
+ amendLibraryField);
}
public Map<String, String> getRewritePrefix() {
return rewritePrefix;
}
+ public Set<String> getMaintainPrefix() {
+ return maintainPrefix;
+ }
+
public Map<String, Map<String, String>> getRewriteDerivedPrefix() {
return rewriteDerivedPrefix;
}
@@ -108,6 +129,10 @@
return emulatedInterfaces;
}
+ public Map<DexField, DexType> getRetargetStaticField() {
+ return retargetStaticField;
+ }
+
public Map<DexMethod, DexType> getRetargetMethod() {
return retargetMethod;
}
@@ -140,11 +165,17 @@
return amendLibraryMethod;
}
+ public Map<DexField, FieldAccessFlags> getAmendLibraryField() {
+ return amendLibraryField;
+ }
+
public boolean isEmpty() {
return rewritePrefix.isEmpty()
&& rewriteDerivedPrefix.isEmpty()
&& emulatedInterfaces.isEmpty()
- && retargetMethod.isEmpty();
+ && retargetMethod.isEmpty()
+ && retargetMethodEmulatedDispatch.isEmpty()
+ && retargetStaticField.isEmpty();
}
public static class Builder {
@@ -153,8 +184,10 @@
private final Origin origin;
private final Map<String, String> rewritePrefix;
+ private final Set<String> maintainPrefix;
private final Map<String, Map<String, String>> rewriteDerivedPrefix;
private final Map<DexType, DexType> emulatedInterfaces;
+ private final Map<DexField, DexType> retargetStaticField;
private final Map<DexMethod, DexType> retargetMethod;
private final Map<DexMethod, DexType> retargetMethodEmulatedDispatch;
private final Map<DexType, DexType> legacyBackport;
@@ -163,21 +196,25 @@
private final Set<DexType> dontRetarget;
private final Map<DexType, Set<DexMethod>> wrapperConversions;
private final Map<DexMethod, MethodAccessFlags> amendLibraryMethod;
+ private final Map<DexField, FieldAccessFlags> amendLibraryField;
Builder(Reporter reporter, Origin origin) {
this(
reporter,
origin,
new HashMap<>(),
+ Sets.newIdentityHashSet(),
new HashMap<>(),
new IdentityHashMap<>(),
new IdentityHashMap<>(),
new IdentityHashMap<>(),
new IdentityHashMap<>(),
new IdentityHashMap<>(),
+ new IdentityHashMap<>(),
Sets.newIdentityHashSet(),
Sets.newIdentityHashSet(),
new IdentityHashMap<>(),
+ new IdentityHashMap<>(),
new IdentityHashMap<>());
}
@@ -185,8 +222,10 @@
Reporter reporter,
Origin origin,
Map<String, String> rewritePrefix,
+ Set<String> maintainPrefix,
Map<String, Map<String, String>> rewriteDerivedPrefix,
Map<DexType, DexType> emulateLibraryInterface,
+ Map<DexField, DexType> retargetStaticField,
Map<DexMethod, DexType> retargetMethod,
Map<DexMethod, DexType> retargetMethodEmulatedDispatch,
Map<DexType, DexType> backportCoreLibraryMember,
@@ -194,12 +233,15 @@
Set<DexMethod> dontRewriteInvocation,
Set<DexType> dontRetargetLibMember,
Map<DexType, Set<DexMethod>> wrapperConversions,
- Map<DexMethod, MethodAccessFlags> amendLibrary) {
+ Map<DexMethod, MethodAccessFlags> amendLibraryMethod,
+ Map<DexField, FieldAccessFlags> amendLibraryField) {
this.reporter = reporter;
this.origin = origin;
this.rewritePrefix = new HashMap<>(rewritePrefix);
+ this.maintainPrefix = Sets.newHashSet(maintainPrefix);
this.rewriteDerivedPrefix = new HashMap<>(rewriteDerivedPrefix);
this.emulatedInterfaces = new IdentityHashMap<>(emulateLibraryInterface);
+ this.retargetStaticField = new IdentityHashMap<>(retargetStaticField);
this.retargetMethod = new IdentityHashMap<>(retargetMethod);
this.retargetMethodEmulatedDispatch = new IdentityHashMap<>(retargetMethodEmulatedDispatch);
this.legacyBackport = new IdentityHashMap<>(backportCoreLibraryMember);
@@ -209,7 +251,8 @@
this.dontRetarget = Sets.newIdentityHashSet();
this.dontRetarget.addAll(dontRetargetLibMember);
this.wrapperConversions = new IdentityHashMap<>(wrapperConversions);
- this.amendLibraryMethod = new IdentityHashMap<>(amendLibrary);
+ this.amendLibraryMethod = new IdentityHashMap<>(amendLibraryMethod);
+ this.amendLibraryField = new IdentityHashMap<>(amendLibraryField);
}
// Utility to set values.
@@ -237,6 +280,11 @@
return this;
}
+ public Builder putMaintainPrefix(String prefix) {
+ maintainPrefix.add(prefix);
+ return this;
+ }
+
public Builder putRewriteDerivedPrefix(
String prefixToMatch, String prefixToRewrite, String rewrittenPrefix) {
Map<String, String> map =
@@ -285,6 +333,15 @@
return this;
}
+ public Builder retargetStaticField(DexField key, DexType rewrittenType) {
+ put(
+ retargetStaticField,
+ key,
+ rewrittenType,
+ HumanDesugaredLibrarySpecificationParser.RETARGET_STATIC_FIELD_KEY);
+ return this;
+ }
+
public Builder retargetMethodEmulatedDispatch(DexMethod key, DexType rewrittenType) {
put(
retargetMethodEmulatedDispatch,
@@ -318,12 +375,19 @@
return this;
}
+ public Builder amendLibraryField(DexField member, FieldAccessFlags flags) {
+ amendLibraryField.put(member, flags);
+ return this;
+ }
+
public HumanRewritingFlags build() {
validate();
return new HumanRewritingFlags(
ImmutableMap.copyOf(rewritePrefix),
+ ImmutableSet.copyOf(maintainPrefix),
ImmutableMap.copyOf(rewriteDerivedPrefix),
ImmutableMap.copyOf(emulatedInterfaces),
+ ImmutableMap.copyOf(retargetStaticField),
ImmutableMap.copyOf(retargetMethod),
ImmutableMap.copyOf(retargetMethodEmulatedDispatch),
ImmutableMap.copyOf(legacyBackport),
@@ -331,7 +395,8 @@
ImmutableSet.copyOf(dontRewriteInvocation),
ImmutableSet.copyOf(dontRetarget),
ImmutableMap.copyOf(wrapperConversions),
- ImmutableMap.copyOf(amendLibraryMethod));
+ ImmutableMap.copyOf(amendLibraryMethod),
+ ImmutableMap.copyOf(amendLibraryField));
}
private void validate() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanTopLevelFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanTopLevelFlags.java
index 6f1f435..5383b69 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanTopLevelFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanTopLevelFlags.java
@@ -47,7 +47,7 @@
public static HumanTopLevelFlags testing() {
return new HumanTopLevelFlags(
- AndroidApiLevel.R, "unused", "testing", null, true, ImmutableList.of());
+ AndroidApiLevel.O, "unused", "testing", null, true, ImmutableList.of());
}
public static Builder builder() {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractFieldParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractFieldParser.java
new file mode 100644
index 0000000..8062063
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractFieldParser.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.ir.desugar.desugaredlibrary.humanspecification.memberparser;
+
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+
+/** Parse fields of the form: modifiers* fieldType holder#fieldName */
+public abstract class AbstractFieldParser extends AbstractMemberParser {
+
+ protected AbstractFieldParser(DexItemFactory factory) {
+ super(factory);
+ }
+
+ // TODO(b/218755060): It would be nice to avoid the split regexp and use a nextToken()
+ // method instead, then add a TraversalContinuation.
+ public void parseField(String signature) {
+ String[] tokens = signature.split(SEPARATORS);
+ if (tokens.length < 3) {
+ throw new CompilationError("Desugared library: cannot parse field " + signature);
+ }
+ fieldStart();
+ int first = parseModifiers(tokens);
+ fieldType(stringTypeToDexType(tokens[first]));
+ holderType(stringTypeToDexType(tokens[first + 1]));
+ fieldName(factory.createString(tokens[first + 1 + 1]));
+ fieldEnd();
+ }
+
+ protected abstract void fieldStart();
+
+ protected abstract void fieldEnd();
+
+ protected abstract void fieldType(DexType type);
+
+ protected abstract void holderType(DexType type);
+
+ protected abstract void fieldName(DexString name);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMemberParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMemberParser.java
new file mode 100644
index 0000000..99475b2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMemberParser.java
@@ -0,0 +1,48 @@
+// 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.desugar.desugaredlibrary.humanspecification.memberparser;
+
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.google.common.collect.ImmutableMap;
+import java.util.Map;
+
+public abstract class AbstractMemberParser {
+
+ static final String SEPARATORS = "\\s+|,\\s+|#|\\(|\\)";
+
+ static final Map<String, Integer> MODIFIERS =
+ ImmutableMap.<String, Integer>builder()
+ .put("public", Constants.ACC_PUBLIC)
+ .put("private", Constants.ACC_PRIVATE)
+ .put("protected", Constants.ACC_PROTECTED)
+ .put("final", Constants.ACC_FINAL)
+ .put("abstract", Constants.ACC_ABSTRACT)
+ .put("static", Constants.ACC_STATIC)
+ .build();
+
+ final DexItemFactory factory;
+
+ protected AbstractMemberParser(DexItemFactory factory) {
+ this.factory = factory;
+ }
+
+ DexType stringTypeToDexType(String stringType) {
+ return factory.createType(DescriptorUtils.javaTypeToDescriptor(stringType));
+ }
+
+ int parseModifiers(String[] split) {
+ int index = 0;
+ while (MODIFIERS.containsKey(split[index])) {
+ modifier(MODIFIERS.get(split[index]));
+ index++;
+ }
+ return index;
+ }
+
+ protected abstract void modifier(int access);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMethodParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMethodParser.java
new file mode 100644
index 0000000..1afff88
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/AbstractMethodParser.java
@@ -0,0 +1,48 @@
+// 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.desugar.desugaredlibrary.humanspecification.memberparser;
+
+import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+
+/** Parse methods of the form: modifiers* returnType holder#name(arg0, ..., argN) */
+public abstract class AbstractMethodParser extends AbstractMemberParser {
+
+ protected AbstractMethodParser(DexItemFactory factory) {
+ super(factory);
+ }
+
+ // TODO(b/218755060): It would be nice to avoid the split regexp and use a nextToken()
+ // method instead, then add a TraversalContinuation.
+ public void parseMethod(String signature) {
+ String[] tokens = signature.split(SEPARATORS);
+ if (tokens.length < 3) {
+ throw new CompilationError("Desugared library: cannot parse method " + signature);
+ }
+ methodStart();
+ int first = parseModifiers(tokens);
+ returnType(stringTypeToDexType(tokens[first]));
+ holderType(stringTypeToDexType(tokens[first + 1]));
+ methodName(factory.createString(tokens[first + 1 + 1]));
+ for (int i = first + 3; i < tokens.length; i++) {
+ argType(stringTypeToDexType(tokens[i]));
+ }
+ methodEnd();
+ }
+
+ protected abstract void methodStart();
+
+ protected abstract void methodEnd();
+
+ protected abstract void returnType(DexType type);
+
+ protected abstract void argType(DexType type);
+
+ protected abstract void holderType(DexType type);
+
+ protected abstract void methodName(DexString name);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanFieldParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanFieldParser.java
new file mode 100644
index 0000000..9a5a44d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanFieldParser.java
@@ -0,0 +1,81 @@
+// 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.desugar.desugaredlibrary.humanspecification.memberparser;
+
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessFlags;
+
+public class HumanFieldParser extends AbstractFieldParser {
+
+ // Values accumulated while parsing.
+ private FieldAccessFlags.Builder flagBuilder;
+ private DexType fieldType;
+ private DexType holder;
+ private DexString fieldName;
+ // Resulting values.
+ private DexField field;
+ private FieldAccessFlags flags;
+
+ public HumanFieldParser(DexItemFactory factory) {
+ super(factory);
+ }
+
+ private boolean parsingFinished() {
+ return field != null;
+ }
+
+ public DexField getField() {
+ assert parsingFinished();
+ return field;
+ }
+
+ public FieldAccessFlags getFlags() {
+ assert parsingFinished();
+ return flags;
+ }
+
+ @Override
+ protected void modifier(int access) {
+ assert !parsingFinished();
+ flagBuilder.set(access);
+ }
+
+ @Override
+ protected void holderType(DexType type) {
+ assert !parsingFinished();
+ holder = type;
+ }
+
+ @Override
+ protected void fieldName(DexString name) {
+ assert !parsingFinished();
+ fieldName = name;
+ }
+
+ @Override
+ protected void fieldStart() {
+ flagBuilder = FieldAccessFlags.builder();
+ fieldType = null;
+ holder = null;
+ fieldName = null;
+ field = null;
+ flags = null;
+ }
+
+ @Override
+ protected void fieldEnd() {
+ field = factory.createField(holder, fieldType, fieldName);
+ flags = flagBuilder.build();
+ }
+
+ @Override
+ protected void fieldType(DexType type) {
+ assert !parsingFinished();
+ fieldType = type;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanMethodParser.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanMethodParser.java
similarity index 96%
rename from src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanMethodParser.java
rename to src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanMethodParser.java
index b4bac60..d78267b 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/HumanMethodParser.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/humanspecification/memberparser/HumanMethodParser.java
@@ -2,7 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification;
+package com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.memberparser;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -25,7 +25,7 @@
private DexMethod method;
private MethodAccessFlags flags;
- protected HumanMethodParser(DexItemFactory factory) {
+ public HumanMethodParser(DexItemFactory factory) {
super(factory);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
index 1f52b3d..d974c56 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineDesugaredLibrarySpecification.java
@@ -4,9 +4,11 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.SemanticVersion;
@@ -82,10 +84,18 @@
return rewritingFlags.getRewriteType();
}
+ public Set<DexType> getMaintainType() {
+ return rewritingFlags.getMaintainType();
+ }
+
public Map<DexType, DexType> getRewriteDerivedTypeOnly() {
return rewritingFlags.getRewriteDerivedTypeOnly();
}
+ public Map<DexField, DexField> getStaticFieldRetarget() {
+ return rewritingFlags.getStaticFieldRetarget();
+ }
+
public Map<DexMethod, DexMethod> getStaticRetarget() {
return rewritingFlags.getStaticRetarget();
}
@@ -143,6 +153,10 @@
return rewritingFlags.getAmendLibraryMethod();
}
+ public Map<DexField, FieldAccessFlags> getAmendLibraryFields() {
+ return rewritingFlags.getAmendLibraryField();
+ }
+
public boolean hasRetargeting() {
return rewritingFlags.hasRetargeting();
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
index 00a4747..dcaa744 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/machinespecification/MachineRewritingFlags.java
@@ -4,8 +4,10 @@
package com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
@@ -25,7 +27,9 @@
MachineRewritingFlags(
Map<DexType, DexType> rewriteType,
+ Set<DexType> maintainType,
Map<DexType, DexType> rewriteDerivedTypeOnly,
+ Map<DexField, DexField> staticFieldRetarget,
Map<DexMethod, DexMethod> staticRetarget,
Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget,
Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget,
@@ -35,9 +39,12 @@
Map<DexType, DexType> legacyBackport,
Set<DexType> dontRetarget,
Map<DexType, CustomConversionDescriptor> customConversions,
- Map<DexMethod, MethodAccessFlags> amendLibraryMethods) {
+ Map<DexMethod, MethodAccessFlags> amendLibraryMethods,
+ Map<DexField, FieldAccessFlags> amendLibraryFields) {
this.rewriteType = rewriteType;
+ this.maintainType = maintainType;
this.rewriteDerivedTypeOnly = rewriteDerivedTypeOnly;
+ this.staticFieldRetarget = staticFieldRetarget;
this.staticRetarget = staticRetarget;
this.nonEmulatedVirtualRetarget = nonEmulatedVirtualRetarget;
this.emulatedVirtualRetarget = emulatedVirtualRetarget;
@@ -49,14 +56,20 @@
this.dontRetarget = dontRetarget;
this.customConversions = customConversions;
this.amendLibraryMethod = amendLibraryMethods;
+ this.amendLibraryField = amendLibraryFields;
}
// Rewrites all the references to the keys as well as synthetic types derived from any key.
private final Map<DexType, DexType> rewriteType;
+ // Maintains the references in the desugared library dex file.
+ private final Set<DexType> maintainType;
// Rewrites only synthetic types derived from any key.
private final Map<DexType, DexType> rewriteDerivedTypeOnly;
- // Static methods to retarget, duplicated to library boundaries.
+ // Fields to retarget.
+ private final Map<DexField, DexField> staticFieldRetarget;
+
+ // Static methods to retarget.
private final Map<DexMethod, DexMethod> staticRetarget;
// Virtual methods to retarget, which are guaranteed not to require emulated dispatch.
@@ -83,15 +96,24 @@
private final Set<DexType> dontRetarget;
private final Map<DexType, CustomConversionDescriptor> customConversions;
private final Map<DexMethod, MethodAccessFlags> amendLibraryMethod;
+ private final Map<DexField, FieldAccessFlags> amendLibraryField;
public Map<DexType, DexType> getRewriteType() {
return rewriteType;
}
+ public Set<DexType> getMaintainType() {
+ return maintainType;
+ }
+
public Map<DexType, DexType> getRewriteDerivedTypeOnly() {
return rewriteDerivedTypeOnly;
}
+ public Map<DexField, DexField> getStaticFieldRetarget() {
+ return staticFieldRetarget;
+ }
+
public Map<DexMethod, DexMethod> getStaticRetarget() {
return staticRetarget;
}
@@ -146,10 +168,15 @@
return amendLibraryMethod;
}
+ public Map<DexField, FieldAccessFlags> getAmendLibraryField() {
+ return amendLibraryField;
+ }
+
public boolean hasRetargeting() {
return !staticRetarget.isEmpty()
|| !nonEmulatedVirtualRetarget.isEmpty()
- || !emulatedVirtualRetarget.isEmpty();
+ || !emulatedVirtualRetarget.isEmpty()
+ || !staticFieldRetarget.isEmpty();
}
public boolean isEmulatedInterfaceRewrittenType(DexType type) {
@@ -174,7 +201,10 @@
Builder() {}
private final Map<DexType, DexType> rewriteType = new IdentityHashMap<>();
+ private final ImmutableSet.Builder<DexType> maintainType = ImmutableSet.builder();
private final Map<DexType, DexType> rewriteDerivedTypeOnly = new IdentityHashMap<>();
+ private final ImmutableMap.Builder<DexField, DexField> staticFieldRetarget =
+ ImmutableMap.builder();
private final ImmutableMap.Builder<DexMethod, DexMethod> staticRetarget =
ImmutableMap.builder();
private final ImmutableMap.Builder<DexMethod, DexMethod> nonEmulatedVirtualRetarget =
@@ -192,6 +222,8 @@
ImmutableMap.builder();
private final ImmutableMap.Builder<DexMethod, MethodAccessFlags> amendLibraryMethod =
ImmutableMap.builder();
+ private final ImmutableMap.Builder<DexField, FieldAccessFlags> amendLibraryField =
+ ImmutableMap.builder();
public void rewriteType(DexType src, DexType target) {
assert src != null;
@@ -201,10 +233,19 @@
rewriteType.put(src, target);
}
+ public void maintainType(DexType type) {
+ assert type != null;
+ maintainType.add(type);
+ }
+
public void rewriteDerivedTypeOnly(DexType src, DexType target) {
rewriteDerivedTypeOnly.put(src, target);
}
+ public void putStaticFieldRetarget(DexField src, DexField dest) {
+ staticFieldRetarget.put(src, dest);
+ }
+
public void putStaticRetarget(DexMethod src, DexMethod dest) {
staticRetarget.put(src, dest);
}
@@ -245,6 +286,10 @@
amendLibraryMethod.put(missingReference, flags);
}
+ public void amendLibraryField(DexField missingReference, FieldAccessFlags flags) {
+ amendLibraryField.put(missingReference, flags);
+ }
+
public DexType getRewrittenType(DexType type) {
return rewriteType.get(type);
}
@@ -252,7 +297,9 @@
public MachineRewritingFlags build() {
return new MachineRewritingFlags(
rewriteType,
+ maintainType.build(),
rewriteDerivedTypeOnly,
+ staticFieldRetarget.build(),
staticRetarget.build(),
nonEmulatedVirtualRetarget.build(),
emulatedVirtualRetarget.build(),
@@ -262,7 +309,8 @@
legacyBackport.build(),
dontRetarget.build(),
customConversions.build(),
- amendLibraryMethod.build());
+ amendLibraryMethod.build(),
+ amendLibraryField.build());
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
index a4b984f..a929fb9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/retargeter/DesugaredLibraryRetargeter.java
@@ -6,12 +6,15 @@
import static com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeter.InvokeRetargetingResult.NO_REWRITING;
+import com.android.tools.r8.cf.code.CfFieldInstruction;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.contexts.CompilationContext.MethodProcessingContext;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexEncodedField;
+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.MethodResolutionResult;
@@ -26,6 +29,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.retargeter.DesugaredLibraryRetargeterSynthesizerEventConsumer.DesugaredLibraryRetargeterInstructionEventConsumer;
import java.util.Collection;
import java.util.Collections;
+import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import java.util.function.Function;
@@ -36,6 +40,7 @@
private final AppView<?> appView;
private final DesugaredLibraryRetargeterSyntheticHelper syntheticHelper;
+ private final Map<DexField, DexField> staticFieldRetarget;
private final Map<DexMethod, DexMethod> staticRetarget;
private final Map<DexMethod, DexMethod> nonEmulatedVirtualRetarget;
private final Map<DexMethod, EmulatedDispatchMethodDescriptor> emulatedVirtualRetarget;
@@ -45,6 +50,7 @@
this.syntheticHelper = new DesugaredLibraryRetargeterSyntheticHelper(appView);
MachineDesugaredLibrarySpecification specification =
appView.options().machineDesugaredLibrarySpecification;
+ staticFieldRetarget = specification.getStaticFieldRetarget();
staticRetarget = specification.getStaticRetarget();
nonEmulatedVirtualRetarget = specification.getNonEmulatedVirtualRetarget();
emulatedVirtualRetarget = specification.getEmulatedVirtualRetarget();
@@ -67,20 +73,53 @@
MethodProcessingContext methodProcessingContext,
CfInstructionDesugaringCollection desugaringCollection,
DexItemFactory dexItemFactory) {
- InvokeRetargetingResult invokeRetargetingResult = computeNewInvokeTarget(instruction, context);
-
- if (!invokeRetargetingResult.hasNewInvokeTarget()) {
- return null;
+ if (instruction.isFieldInstruction() && needsDesugaring(instruction, context)) {
+ return desugarFieldInstruction(instruction.asFieldInstruction(), context);
+ } else if (instruction.isInvoke() && needsDesugaring(instruction, context)) {
+ return desugarInvoke(instruction.asInvoke(), eventConsumer, context);
}
+ return null;
+ }
+ private Collection<CfInstruction> desugarFieldInstruction(
+ CfFieldInstruction fieldInstruction, ProgramMethod context) {
+ DexField fieldRetarget = fieldRetarget(fieldInstruction, context);
+ assert fieldRetarget != null;
+ assert fieldInstruction.isStaticFieldGet() || fieldInstruction.isStaticFieldPut();
+ return Collections.singletonList(fieldInstruction.createWithField(fieldRetarget));
+ }
+
+ private List<CfInstruction> desugarInvoke(
+ CfInvoke invoke, CfInstructionDesugaringEventConsumer eventConsumer, ProgramMethod context) {
+ InvokeRetargetingResult invokeRetargetingResult = computeNewInvokeTarget(invoke, context);
+ assert invokeRetargetingResult.hasNewInvokeTarget();
DexMethod newInvokeTarget = invokeRetargetingResult.getNewInvokeTarget(eventConsumer);
return Collections.singletonList(
- new CfInvoke(Opcodes.INVOKESTATIC, newInvokeTarget, instruction.asInvoke().isInterface()));
+ new CfInvoke(Opcodes.INVOKESTATIC, newInvokeTarget, invoke.isInterface()));
}
@Override
public boolean needsDesugaring(CfInstruction instruction, ProgramMethod context) {
- return computeNewInvokeTarget(instruction, context).hasNewInvokeTarget();
+ if (instruction.isFieldInstruction()) {
+ return fieldRetarget(instruction.asFieldInstruction(), context) != null;
+ } else if (instruction.isInvoke()) {
+ return computeNewInvokeTarget(instruction.asInvoke(), context).hasNewInvokeTarget();
+ }
+ return false;
+ }
+
+ private DexField fieldRetarget(CfFieldInstruction fieldInstruction, ProgramMethod context) {
+ DexEncodedField resolvedField =
+ appView
+ .appInfoForDesugaring()
+ .resolveField(fieldInstruction.getField(), context)
+ .getResolvedField();
+ if (resolvedField != null) {
+ assert resolvedField.isStatic()
+ || !staticFieldRetarget.containsKey(resolvedField.getReference());
+ return staticFieldRetarget.get(resolvedField.getReference());
+ }
+ return null;
}
InvokeRetargetingResult ensureInvokeRetargetingResult(DexMethod retarget) {
@@ -124,10 +163,7 @@
}
private InvokeRetargetingResult computeNewInvokeTarget(
- CfInstruction instruction, ProgramMethod context) {
- if (!instruction.isInvoke()) {
- return NO_REWRITING;
- }
+ CfInvoke instruction, ProgramMethod context) {
if (appView
.options()
.machineDesugaredLibrarySpecification
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
index 87c03e3..78fc59f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachinePrefixConverter.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.ir.desugar.desugaredlibrary.machinespecification.MachineRewritingFlags;
import com.android.tools.r8.utils.DescriptorUtils;
import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.Map;
import java.util.Set;
@@ -25,6 +26,7 @@
private final String synthesizedPrefix;
private final boolean libraryCompilation;
private final Map<DexString, DexString> descriptorPrefix;
+ private final Set<DexString> descriptorMaintainPrefix;
private final Map<DexString, Map<DexString, DexString>> descriptorDifferentPrefix;
private final Set<DexString> usedPrefix = Sets.newIdentityHashSet();
@@ -38,6 +40,7 @@
this.synthesizedPrefix = humanSpec.getSynthesizedLibraryClassesPackagePrefix();
this.libraryCompilation = humanSpec.isLibraryCompilation();
this.descriptorPrefix = convertRewritePrefix(rewritingFlags.getRewritePrefix());
+ this.descriptorMaintainPrefix = convertMaintainPrefix(rewritingFlags.getMaintainPrefix());
this.descriptorDifferentPrefix =
convertRewriteDifferentPrefix(rewritingFlags.getRewriteDerivedPrefix());
}
@@ -56,6 +59,7 @@
private void warnIfUnusedPrefix(BiConsumer<String, Set<DexString>> warnConsumer) {
Set<DexString> prefixes = Sets.newIdentityHashSet();
prefixes.addAll(descriptorPrefix.keySet());
+ prefixes.addAll(descriptorMaintainPrefix);
prefixes.addAll(descriptorDifferentPrefix.keySet());
prefixes.removeAll(usedPrefix);
warnConsumer.accept("The following prefixes do not match any type: ", prefixes);
@@ -99,6 +103,7 @@
private void registerClassType(DexType type) {
registerType(type);
+ registerMaintainType(type);
registerDifferentType(type);
}
@@ -109,6 +114,15 @@
}
}
+ private void registerMaintainType(DexType type) {
+ DexString prefix = prefixMatching(type, descriptorMaintainPrefix);
+ if (prefix == null) {
+ return;
+ }
+ builder.maintainType(type);
+ usedPrefix.add(prefix);
+ }
+
private void registerDifferentType(DexType type) {
DexString prefix = prefixMatching(type, descriptorDifferentPrefix.keySet());
if (prefix == null) {
@@ -160,6 +174,14 @@
return mapBuilder.build();
}
+ private ImmutableSet<DexString> convertMaintainPrefix(Set<String> maintainPrefix) {
+ ImmutableSet.Builder<DexString> builder = ImmutableSet.builder();
+ for (String prefix : maintainPrefix) {
+ builder.add(toDescriptorPrefix(prefix));
+ }
+ return builder.build();
+ }
+
private ImmutableMap<DexString, DexString> convertRewritePrefix(
Map<String, String> rewritePrefix) {
ImmutableMap.Builder<DexString, DexString> mapBuilder = ImmutableMap.builder();
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
index f64a3d0..56af1fc 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/desugaredlibrary/specificationconversion/HumanToMachineRetargetConverter.java
@@ -6,7 +6,9 @@
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexReference;
@@ -26,7 +28,7 @@
public class HumanToMachineRetargetConverter {
private final AppInfoWithClassHierarchy appInfo;
- private final Set<DexMethod> missingMethods = Sets.newIdentityHashSet();
+ private final Set<DexReference> missingReferences = Sets.newIdentityHashSet();
public HumanToMachineRetargetConverter(AppInfoWithClassHierarchy appInfo) {
this.appInfo = appInfo;
@@ -37,6 +39,9 @@
MachineRewritingFlags.Builder builder,
BiConsumer<String, Set<? extends DexReference>> warnConsumer) {
rewritingFlags
+ .getRetargetStaticField()
+ .forEach((field, type) -> convertRetargetField(builder, field, type));
+ rewritingFlags
.getRetargetMethod()
.forEach((method, type) -> convertRetargetMethod(builder, method, type));
rewritingFlags
@@ -44,7 +49,19 @@
.forEach(
(method, type) ->
convertRetargetMethodEmulatedDispatch(builder, rewritingFlags, method, type));
- warnConsumer.accept("Cannot retarget missing methods: ", missingMethods);
+ warnConsumer.accept("Cannot retarget missing references: ", missingReferences);
+ }
+
+ private void convertRetargetField(
+ MachineRewritingFlags.Builder builder, DexField field, DexType type) {
+ DexClass holder = appInfo.definitionFor(field.holder);
+ DexEncodedField foundField = holder.lookupField(field);
+ if (foundField == null) {
+ missingReferences.add(field);
+ return;
+ }
+ builder.putStaticFieldRetarget(
+ field, appInfo.dexItemFactory().createField(type, field.type, field.name));
}
private void convertRetargetMethodEmulatedDispatch(
@@ -55,7 +72,7 @@
DexClass holder = appInfo.definitionFor(method.holder);
DexEncodedMethod foundMethod = holder.lookupMethod(method);
if (foundMethod == null) {
- missingMethods.add(method);
+ missingReferences.add(method);
return;
}
if (foundMethod.isStatic()) {
@@ -83,7 +100,7 @@
DexClass holder = appInfo.definitionFor(method.holder);
DexEncodedMethod foundMethod = holder.lookupMethod(method);
if (foundMethod == null) {
- missingMethods.add(method);
+ missingReferences.add(method);
return;
}
if (foundMethod.isStatic()) {
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 5ea225d..0cec776 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
@@ -86,8 +86,13 @@
HumanRewritingFlags rewritingFlags = humanSpec.getRewritingFlags();
MachineRewritingFlags.Builder builder = MachineRewritingFlags.builder();
DesugaredLibraryAmender.run(
- rewritingFlags.getAmendLibraryMethod(), appInfo, reporter, ComputedApiLevel.unknown());
+ rewritingFlags.getAmendLibraryMethod(),
+ rewritingFlags.getAmendLibraryField(),
+ appInfo,
+ reporter,
+ ComputedApiLevel.unknown());
rewritingFlags.getAmendLibraryMethod().forEach(builder::amendLibraryMethod);
+ rewritingFlags.getAmendLibraryField().forEach(builder::amendLibraryField);
new HumanToMachineRetargetConverter(appInfo)
.convertRetargetFlags(rewritingFlags, builder, this::warnMissingReferences);
new HumanToMachineEmulatedInterfaceConverter(appInfo)
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
index b1c59bc..4446275 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/ClassProcessor.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GenericSignature;
import com.android.tools.r8.graph.GenericSignature.ClassTypeSignature;
+import com.android.tools.r8.graph.LookupMethodTarget;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.MethodResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
@@ -717,8 +718,9 @@
}
}
assert resolutionResult.isSuccessfulMemberResolutionResult();
- DexClassAndMethod virtualDispatchTarget =
+ LookupMethodTarget lookupMethodTarget =
resolutionResult.lookupVirtualDispatchTarget(clazz, appInfo);
+ DexClassAndMethod virtualDispatchTarget = lookupMethodTarget.getTarget();
assert virtualDispatchTarget != null;
// If resolution targets a default interface method, forward it.
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
index dc739bb..3919202 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/itf/InterfaceDesugaringSyntheticHelper.java
@@ -98,6 +98,13 @@
if (isEmulatedInterface(clazz.type)) {
return true;
}
+ if (appView
+ .options()
+ .machineDesugaredLibrarySpecification
+ .getMaintainType()
+ .contains(clazz.type)) {
+ return true;
+ }
return appView.typeRewriter.hasRewrittenType(clazz.type, appView);
}
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 2ae7d7d..778ed23 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
@@ -713,7 +713,10 @@
DexClass clazz, DexMethod invokedMethod, ProgramMethod context) {
DexClassAndMethod superTarget =
appView.appInfoForDesugaring().lookupSuperTarget(invokedMethod, context);
- if (clazz.isInterface() && appView.typeRewriter.hasRewrittenType(clazz.type, appView)) {
+ if (clazz.isInterface()
+ && clazz.isLibraryClass()
+ && helper.isInDesugaredLibrary(clazz)
+ && !helper.isEmulatedInterface(clazz.type)) {
if (superTarget != null && superTarget.getDefinition().isDefaultMethod()) {
DexClass holder = superTarget.getHolder();
if (holder.isLibraryClass() && holder.isInterface()) {
diff --git a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/DefaultOpenClosedInterfacesCollection.java b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/DefaultOpenClosedInterfacesCollection.java
index df264e4..f8aeb81 100644
--- a/src/main/java/com/android/tools/r8/optimize/interfaces/collection/DefaultOpenClosedInterfacesCollection.java
+++ b/src/main/java/com/android/tools/r8/optimize/interfaces/collection/DefaultOpenClosedInterfacesCollection.java
@@ -22,7 +22,8 @@
@Override
public boolean isDefinitelyClosed(DexClass clazz) {
- return false;
+ // TODO(b/214496607): Should return false.
+ return true;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 8b8e13b..eac02d2 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -36,6 +36,7 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
import com.android.tools.r8.graph.InstantiatedSubTypeInfo;
+import com.android.tools.r8.graph.LookupMethodTarget;
import com.android.tools.r8.graph.LookupResult.LookupResultSuccess;
import com.android.tools.r8.graph.LookupTarget;
import com.android.tools.r8.graph.MethodAccessInfoCollection;
@@ -1467,17 +1468,17 @@
if (receiverLowerBoundType != null
&& receiverLowerBoundType.getClassType() == refinedReceiverType) {
if (refinedReceiverClass.isProgramClass()) {
- DexClassAndMethod clazzAndMethod =
+ LookupMethodTarget methodTarget =
resolution.lookupVirtualDispatchTarget(refinedReceiverClass.asProgramClass(), this);
- if (clazzAndMethod == null
- || (clazzAndMethod.isProgramMethod()
+ if (methodTarget == null
+ || (methodTarget.getTarget().isProgramMethod()
&& !getKeepInfo()
- .getMethodInfo(clazzAndMethod.asProgramMethod())
+ .getMethodInfo(methodTarget.getTarget().asProgramMethod())
.isOptimizationAllowed(options()))) {
// TODO(b/150640456): We should maybe only consider program methods.
return DexEncodedMethod.SENTINEL;
}
- return clazzAndMethod.getDefinition();
+ return methodTarget.getDefinition();
} else {
// TODO(b/150640456): We should maybe only consider program methods.
// If we resolved to a method on the refined receiver in the library, then we report the
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index c7917ce..7d54b09 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -66,6 +66,7 @@
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.InvalidCode;
import com.android.tools.r8.graph.LookupLambdaTarget;
+import com.android.tools.r8.graph.LookupMethodTarget;
import com.android.tools.r8.graph.LookupResult;
import com.android.tools.r8.graph.LookupTarget;
import com.android.tools.r8.graph.MethodAccessInfoCollection;
@@ -3277,20 +3278,25 @@
private void markVirtualDispatchTargetAsLive(
LookupTarget target, Function<ProgramMethod, KeepReasonWitness> reason) {
target.accept(
- method -> markVirtualDispatchTargetAsLive(method, reason),
- lambda -> markVirtualDispatchTargetAsLive(lambda, reason));
+ method -> markVirtualDispatchMethodTargetAsLive(method, reason),
+ lambda -> markVirtualDispatchLambdaTargetAsLive(lambda, reason));
analyses.forEach(analysis -> analysis.notifyMarkVirtualDispatchTargetAsLive(target, workList));
}
- private void markVirtualDispatchTargetAsLive(
- DexClassAndMethod target, Function<ProgramMethod, KeepReasonWitness> reason) {
- ProgramMethod programMethod = target.asProgramMethod();
+ private void markVirtualDispatchMethodTargetAsLive(
+ LookupMethodTarget target, Function<ProgramMethod, KeepReasonWitness> reason) {
+ ProgramMethod programMethod = target.getTarget().asProgramMethod();
if (programMethod != null && !programMethod.getDefinition().isAbstract()) {
- markVirtualMethodAsLive(programMethod, reason.apply(programMethod));
+ KeepReasonWitness appliedReason = reason.apply(programMethod);
+ markVirtualMethodAsLive(programMethod, appliedReason);
+ DexClassAndMethod accessOverride = target.getAccessOverride();
+ if (accessOverride != null && accessOverride.isProgramMethod()) {
+ markMethodAsTargeted(accessOverride.asProgramMethod(), appliedReason);
+ }
}
}
- private void markVirtualDispatchTargetAsLive(
+ private void markVirtualDispatchLambdaTargetAsLive(
LookupLambdaTarget target, Function<ProgramMethod, KeepReasonWitness> reason) {
ProgramMethod implementationMethod = target.getImplementationMethod().asProgramMethod();
if (implementationMethod != null) {
@@ -4434,7 +4440,7 @@
if (override.isLambdaTarget()) {
return true;
}
- ProgramMethod programMethod = override.asMethodTarget().asProgramMethod();
+ ProgramMethod programMethod = override.asMethodTarget().getTarget().asProgramMethod();
if (programMethod == null) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
index 46e77e8..d462818 100644
--- a/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/L8TreePruner.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.desugar.TypeRewriter;
import com.android.tools.r8.utils.InternalOptions;
-import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.IdentityHashMap;
import java.util.List;
@@ -22,25 +21,24 @@
public class L8TreePruner {
private final InternalOptions options;
- private final Set<DexType> emulatedInterfaces = Sets.newIdentityHashSet();
- private final Set<DexType> backports = Sets.newIdentityHashSet();
private final List<DexType> pruned = new ArrayList<>();
public L8TreePruner(InternalOptions options) {
this.options = options;
- backports.addAll(options.machineDesugaredLibrarySpecification.getLegacyBackport().keySet());
- emulatedInterfaces.addAll(
- options.machineDesugaredLibrarySpecification.getEmulatedInterfaces().keySet());
}
public DexApplication prune(DexApplication app, TypeRewriter typeRewriter) {
+ Set<DexType> maintainType = options.machineDesugaredLibrarySpecification.getMaintainType();
+ Set<DexType> emulatedInterfaces =
+ options.machineDesugaredLibrarySpecification.getEmulatedInterfaces().keySet();
Map<DexType, DexProgramClass> typeMap = new IdentityHashMap<>();
List<DexProgramClass> toKeep = new ArrayList<>();
boolean pruneNestMember = false;
for (DexProgramClass aClass : app.classes()) {
typeMap.put(aClass.type, aClass);
if (typeRewriter.hasRewrittenType(aClass.type, null)
- || emulatedInterfaces.contains(aClass.type)) {
+ || emulatedInterfaces.contains(aClass.type)
+ || maintainType.contains(aClass.type)) {
toKeep.add(aClass);
} else {
pruneNestMember |= aClass.isInANest();
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
index ceb9a37..67dbe6a 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMarker.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
+import java.nio.charset.StandardCharsets;
import org.objectweb.asm.Attribute;
import org.objectweb.asm.ByteVector;
import org.objectweb.asm.ClassReader;
@@ -23,33 +24,51 @@
public class SyntheticMarker {
private static final String SYNTHETIC_MARKER_ATTRIBUTE_TYPE_NAME =
- "com.android.tools.r8.SynthesizedClass";
+ "com.android.tools.r8.SynthesizedClassV2";
public static Attribute getMarkerAttributePrototype(SyntheticNaming syntheticNaming) {
- return new MarkerAttribute(null, syntheticNaming);
+ return new MarkerAttribute(null, null, syntheticNaming);
}
public static void writeMarkerAttribute(
ClassWriter writer, SyntheticKind kind, SyntheticItems syntheticItems) {
- writer.visitAttribute(new MarkerAttribute(kind, syntheticItems.getNaming()));
+ SyntheticNaming naming = syntheticItems.getNaming();
+ writer.visitAttribute(new MarkerAttribute(kind, naming.getVersionHash(), naming));
}
public static SyntheticMarker readMarkerAttribute(Attribute attribute) {
if (attribute instanceof MarkerAttribute) {
MarkerAttribute marker = (MarkerAttribute) attribute;
- return new SyntheticMarker(marker.kind, null);
+ if (marker.versionHash.equals(marker.syntheticNaming.getVersionHash())) {
+ return new SyntheticMarker(marker.kind, null);
+ }
}
return null;
}
+ /**
+ * CF attribute for marking synthetic classes.
+ *
+ * <p>The attribute name is defined by {@code SYNTHETIC_MARKER_ATTRIBUTE_TYPE_NAME}. The format of
+ * the attribute payload is
+ *
+ * <pre>
+ * u2 syntheticKindId
+ * u2 versionHashLength
+ * u1[versionHashLength] versionHashBytes
+ * </pre>
+ */
private static class MarkerAttribute extends Attribute {
- private SyntheticKind kind;
+ private final SyntheticKind kind;
+ private final String versionHash;
private final SyntheticNaming syntheticNaming;
- public MarkerAttribute(SyntheticKind kind, SyntheticNaming syntheticNaming) {
+ public MarkerAttribute(
+ SyntheticKind kind, String versionHash, SyntheticNaming syntheticNaming) {
super(SYNTHETIC_MARKER_ATTRIBUTE_TYPE_NAME);
this.kind = kind;
+ this.versionHash = versionHash;
this.syntheticNaming = syntheticNaming;
}
@@ -61,18 +80,29 @@
char[] charBuffer,
int codeAttributeOffset,
Label[] labels) {
- short id = classReader.readShort(offset);
- assert id >= 0;
- SyntheticKind kind = syntheticNaming.fromId(id);
- return new MarkerAttribute(kind, syntheticNaming);
+ short syntheticKindId = classReader.readShort(offset);
+ offset += 2;
+ short versionHashLength = classReader.readShort(offset);
+ offset += 2;
+ byte[] versionHashBytes = new byte[versionHashLength];
+ for (int i = 0; i < versionHashLength; i++) {
+ versionHashBytes[i] = (byte) classReader.readByte(offset++);
+ }
+ assert syntheticKindId >= 0;
+ SyntheticKind kind = syntheticNaming.fromId(syntheticKindId);
+ String versionHash = new String(versionHashBytes, StandardCharsets.UTF_8);
+ return new MarkerAttribute(kind, versionHash, syntheticNaming);
}
@Override
protected ByteVector write(
ClassWriter classWriter, byte[] code, int codeLength, int maxStack, int maxLocals) {
- ByteVector byteVector = new ByteVector();
assert 0 <= kind.getId() && kind.getId() <= Short.MAX_VALUE;
+ ByteVector byteVector = new ByteVector();
byteVector.putShort(kind.getId());
+ byte[] versionHashBytes = versionHash.getBytes(StandardCharsets.UTF_8);
+ byteVector.putShort(versionHashBytes.length);
+ byteVector.putByteArray(versionHashBytes, 0, versionHashBytes.length);
return byteVector;
}
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index edc591e..3559fe3 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.synthesis;
+import com.android.tools.r8.Version;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
@@ -12,131 +13,143 @@
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.structural.Equatable;
import com.android.tools.r8.utils.structural.Ordered;
-import it.unimi.dsi.fastutil.ints.IntArraySet;
-import it.unimi.dsi.fastutil.ints.IntSet;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
+import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
public class SyntheticNaming {
- public SyntheticNaming() {}
-
private KindGenerator generator = new KindGenerator();
// Global synthetics.
- public final SyntheticKind RECORD_TAG = generator.forGlobalClass(1);
- public final SyntheticKind API_MODEL_STUB = generator.forGlobalClass(33);
+ public final SyntheticKind RECORD_TAG = generator.forGlobalClass();
+ public final SyntheticKind API_MODEL_STUB = generator.forGlobalClass();
// Classpath only synthetics in the global type namespace.
- public final SyntheticKind RETARGET_STUB = generator.forGlobalClasspathClass(36);
- public final SyntheticKind EMULATED_INTERFACE_MARKER_CLASS =
- generator.forGlobalClasspathClass(29);
+ public final SyntheticKind RETARGET_STUB = generator.forGlobalClasspathClass();
+ public final SyntheticKind EMULATED_INTERFACE_MARKER_CLASS = generator.forGlobalClasspathClass();
// Fixed suffix synthetics. Each has a hygienic prefix type.
public final SyntheticKind ENUM_UNBOXING_LOCAL_UTILITY_CLASS =
- generator.forFixedClass(24, "$EnumUnboxingLocalUtility");
+ generator.forFixedClass("$EnumUnboxingLocalUtility");
public final SyntheticKind ENUM_UNBOXING_SHARED_UTILITY_CLASS =
- generator.forFixedClass(25, "$EnumUnboxingSharedUtility");
- public final SyntheticKind COMPANION_CLASS = generator.forFixedClass(2, "$-CC");
+ generator.forFixedClass("$EnumUnboxingSharedUtility");
+ public final SyntheticKind COMPANION_CLASS = generator.forFixedClass("$-CC");
public final SyntheticKind EMULATED_INTERFACE_CLASS =
- generator.forFixedClass(3, InterfaceDesugaringForTesting.EMULATED_INTERFACE_CLASS_SUFFIX);
- public final SyntheticKind RETARGET_CLASS = generator.forFixedClass(20, "RetargetClass");
- public final SyntheticKind RETARGET_INTERFACE = generator.forFixedClass(21, "RetargetInterface");
- public final SyntheticKind WRAPPER = generator.forFixedClass(22, "$Wrapper");
- public final SyntheticKind VIVIFIED_WRAPPER = generator.forFixedClass(23, "$VivifiedWrapper");
- public final SyntheticKind INIT_TYPE_ARGUMENT = generator.forFixedClass(5, "-IA");
+ generator.forFixedClass(InterfaceDesugaringForTesting.EMULATED_INTERFACE_CLASS_SUFFIX);
+ public final SyntheticKind RETARGET_CLASS = generator.forFixedClass("RetargetClass");
+ public final SyntheticKind RETARGET_INTERFACE = generator.forFixedClass("RetargetInterface");
+ public final SyntheticKind WRAPPER = generator.forFixedClass("$Wrapper");
+ public final SyntheticKind VIVIFIED_WRAPPER = generator.forFixedClass("$VivifiedWrapper");
+ public final SyntheticKind INIT_TYPE_ARGUMENT = generator.forFixedClass("-IA");
public final SyntheticKind HORIZONTAL_INIT_TYPE_ARGUMENT_1 =
- generator.forFixedClass(6, SYNTHETIC_CLASS_SEPARATOR + "IA$1");
+ generator.forFixedClass(SYNTHETIC_CLASS_SEPARATOR + "IA$1");
public final SyntheticKind HORIZONTAL_INIT_TYPE_ARGUMENT_2 =
- generator.forFixedClass(7, SYNTHETIC_CLASS_SEPARATOR + "IA$2");
+ generator.forFixedClass(SYNTHETIC_CLASS_SEPARATOR + "IA$2");
public final SyntheticKind HORIZONTAL_INIT_TYPE_ARGUMENT_3 =
- generator.forFixedClass(8, SYNTHETIC_CLASS_SEPARATOR + "IA$3");
- public final SyntheticKind ENUM_CONVERSION = generator.forFixedClass(31, "$EnumConversion");
+ generator.forFixedClass(SYNTHETIC_CLASS_SEPARATOR + "IA$3");
+ public final SyntheticKind ENUM_CONVERSION = generator.forFixedClass("$EnumConversion");
// Locally generated synthetic classes.
- public final SyntheticKind LAMBDA = generator.forInstanceClass(4, "Lambda");
+ public final SyntheticKind LAMBDA = generator.forInstanceClass("Lambda");
// TODO(b/214901256): Sharing of synthetic classes may lead to duplicate method errors.
public final SyntheticKind NON_FIXED_INIT_TYPE_ARGUMENT =
- generator.forNonSharableInstanceClass(35, "$IA");
- public final SyntheticKind CONST_DYNAMIC = generator.forInstanceClass(30, "$Condy");
+ generator.forNonSharableInstanceClass("$IA");
+ public final SyntheticKind CONST_DYNAMIC = generator.forInstanceClass("$Condy");
// Method synthetics.
public final SyntheticKind ENUM_UNBOXING_CHECK_NOT_ZERO_METHOD =
- generator.forSingleMethod(27, "CheckNotZero");
- public final SyntheticKind RECORD_HELPER = generator.forSingleMethod(9, "Record");
- public final SyntheticKind BACKPORT = generator.forSingleMethod(10, "Backport");
+ generator.forSingleMethod("CheckNotZero");
+ public final SyntheticKind RECORD_HELPER = generator.forSingleMethod("Record");
+ public final SyntheticKind BACKPORT = generator.forSingleMethod("Backport");
public final SyntheticKind BACKPORT_WITH_FORWARDING =
- generator.forSingleMethod(34, "BackportWithForwarding");
+ generator.forSingleMethod("BackportWithForwarding");
public final SyntheticKind STATIC_INTERFACE_CALL =
- generator.forSingleMethod(11, "StaticInterfaceCall");
- public final SyntheticKind TO_STRING_IF_NOT_NULL =
- generator.forSingleMethod(12, "ToStringIfNotNull");
- public final SyntheticKind THROW_CCE_IF_NOT_NULL =
- generator.forSingleMethod(13, "ThrowCCEIfNotNull");
- public final SyntheticKind THROW_IAE = generator.forSingleMethod(14, "ThrowIAE");
- public final SyntheticKind THROW_ICCE = generator.forSingleMethod(15, "ThrowICCE");
- public final SyntheticKind THROW_NSME = generator.forSingleMethod(16, "ThrowNSME");
- public final SyntheticKind TWR_CLOSE_RESOURCE = generator.forSingleMethod(17, "TwrCloseResource");
- public final SyntheticKind SERVICE_LOADER = generator.forSingleMethod(18, "ServiceLoad");
- public final SyntheticKind OUTLINE = generator.forSingleMethod(19, "Outline");
- public final SyntheticKind API_CONVERSION = generator.forSingleMethod(26, "APIConversion");
+ generator.forSingleMethod("StaticInterfaceCall");
+ public final SyntheticKind TO_STRING_IF_NOT_NULL = generator.forSingleMethod("ToStringIfNotNull");
+ public final SyntheticKind THROW_CCE_IF_NOT_NULL = generator.forSingleMethod("ThrowCCEIfNotNull");
+ public final SyntheticKind THROW_IAE = generator.forSingleMethod("ThrowIAE");
+ public final SyntheticKind THROW_ICCE = generator.forSingleMethod("ThrowICCE");
+ public final SyntheticKind THROW_NSME = generator.forSingleMethod("ThrowNSME");
+ public final SyntheticKind TWR_CLOSE_RESOURCE = generator.forSingleMethod("TwrCloseResource");
+ public final SyntheticKind SERVICE_LOADER = generator.forSingleMethod("ServiceLoad");
+ public final SyntheticKind OUTLINE = generator.forSingleMethod("Outline");
+ public final SyntheticKind API_CONVERSION = generator.forSingleMethod("APIConversion");
public final SyntheticKind API_CONVERSION_PARAMETERS =
- generator.forSingleMethod(28, "APIConversionParameters");
- public final SyntheticKind ARRAY_CONVERSION = generator.forSingleMethod(37, "$ArrayConversion");
- public final SyntheticKind API_MODEL_OUTLINE = generator.forSingleMethod(32, "ApiModelOutline");
+ generator.forSingleMethod("APIConversionParameters");
+ public final SyntheticKind ARRAY_CONVERSION = generator.forSingleMethod("$ArrayConversion");
+ public final SyntheticKind API_MODEL_OUTLINE = generator.forSingleMethod("ApiModelOutline");
- private final List<SyntheticKind> ALL_KINDS = generator.getAllKinds();
+ private final String versionHash;
+ private final List<SyntheticKind> ALL_KINDS;
+
+ public SyntheticNaming() {
+ generator.hasher.putString(Version.getVersionString(), StandardCharsets.UTF_8);
+ versionHash = generator.hasher.hash().toString();
+ ALL_KINDS = generator.getAllKinds();
+ generator = null;
+ }
+
+ public String getVersionHash() {
+ return versionHash;
+ }
public Collection<SyntheticKind> kinds() {
return ALL_KINDS;
}
public SyntheticKind fromId(int id) {
- for (SyntheticKind kind : ALL_KINDS) {
- if (kind.getId() == id) {
- return kind;
- }
+ if (0 < id && id <= ALL_KINDS.size()) {
+ return ALL_KINDS.get(id - 1);
}
return null;
}
private static class KindGenerator {
+ private int nextId = 1;
private List<SyntheticKind> kinds = new ArrayList<>();
- private IntSet usedIds = new IntArraySet();
+ private Hasher hasher = Hashing.sha256().newHasher();
private SyntheticKind register(SyntheticKind kind) {
- if (!usedIds.add(kind.getId())) {
- throw new Unreachable("Invalid reuse of synthetic kind id: " + kind.getId());
- }
+ kind.hash(hasher);
kinds.add(kind);
+ if (kinds.size() != kind.getId()) {
+ throw new Unreachable("Invalid synthetic kind id: " + kind.getId());
+ }
return kind;
}
- SyntheticKind forSingleMethod(int id, String descriptor) {
- return register(new SyntheticMethodKind(id, descriptor));
+ private int getNextId() {
+ return nextId++;
+ }
+
+ SyntheticKind forSingleMethod(String descriptor) {
+ return register(new SyntheticMethodKind(getNextId(), descriptor));
}
// TODO(b/214901256): Remove once fixed.
- SyntheticKind forNonSharableInstanceClass(int id, String descriptor) {
- return register(new SyntheticClassKind(id, descriptor, false));
+ SyntheticKind forNonSharableInstanceClass(String descriptor) {
+ return register(new SyntheticClassKind(getNextId(), descriptor, false));
}
- SyntheticKind forInstanceClass(int id, String descriptor) {
- return register(new SyntheticClassKind(id, descriptor, true));
+ SyntheticKind forInstanceClass(String descriptor) {
+ return register(new SyntheticClassKind(getNextId(), descriptor, true));
}
- SyntheticKind forFixedClass(int id, String descriptor) {
- return register(new SyntheticFixedClassKind(id, descriptor, false));
+ SyntheticKind forFixedClass(String descriptor) {
+ return register(new SyntheticFixedClassKind(getNextId(), descriptor, false));
}
- SyntheticKind forGlobalClass(int id) {
- return register(new SyntheticFixedClassKind(id, "", true));
+ SyntheticKind forGlobalClass() {
+ return register(new SyntheticFixedClassKind(getNextId(), "", true));
}
- SyntheticKind forGlobalClasspathClass(int id) {
- return register(new SyntheticFixedClassKind(id, "", false));
+ SyntheticKind forGlobalClasspathClass() {
+ return register(new SyntheticFixedClassKind(getNextId(), "", false));
}
List<SyntheticKind> getAllKinds() {
@@ -198,6 +211,13 @@
public abstract boolean isMayOverridesNonProgramType();
+ public final void hash(Hasher hasher) {
+ hasher.putInt(getId());
+ hasher.putString(getDescriptor(), StandardCharsets.UTF_8);
+ internalHash(hasher);
+ }
+
+ public abstract void internalHash(Hasher hasher);
}
private static class SyntheticMethodKind extends SyntheticKind {
@@ -232,6 +252,10 @@
return false;
}
+ @Override
+ public void internalHash(Hasher hasher) {
+ hasher.putString("method", StandardCharsets.UTF_8);
+ }
}
private static class SyntheticClassKind extends SyntheticKind {
@@ -269,6 +293,11 @@
return false;
}
+ @Override
+ public void internalHash(Hasher hasher) {
+ hasher.putString("class", StandardCharsets.UTF_8);
+ hasher.putBoolean(sharable);
+ }
}
private static class SyntheticFixedClassKind extends SyntheticClassKind {
@@ -299,6 +328,11 @@
return mayOverridesNonProgramType;
}
+ @Override
+ public void internalHash(Hasher hasher) {
+ hasher.putString(isGlobal() ? "global" : "fixed", StandardCharsets.UTF_8);
+ hasher.putBoolean(mayOverridesNonProgramType);
+ }
}
private static final String SYNTHETIC_CLASS_SEPARATOR = "$$";
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 50c315a..309e92a5 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -25,7 +25,6 @@
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.dump.DumpOptions;
import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.errors.ExperimentalClassFileVersionDiagnostic;
import com.android.tools.r8.errors.IncompleteNestNestDesugarDiagnosic;
import com.android.tools.r8.errors.InterfaceDesugarMissingTypeDiagnostic;
import com.android.tools.r8.errors.InvalidDebugInfoException;
@@ -108,6 +107,7 @@
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
import org.objectweb.asm.Opcodes;
public class InternalOptions implements GlobalKeepInfoConfiguration {
@@ -138,7 +138,6 @@
}
public static final CfVersion SUPPORTED_CF_VERSION = CfVersion.V17;
- public static final CfVersion EXPERIMENTAL_CF_VERSION = CfVersion.V14;
public static final int SUPPORTED_DEX_VERSION =
AndroidApiLevel.LATEST.getDexVersion().getIntValue();
@@ -272,9 +271,34 @@
// Flag to toggle if DEX code objects should pass-through without IR processing.
public boolean passthroughDexCode = false;
+ public static class NeverMergeGroup<T> {
+ private final List<T> prefixes;
+ private final List<T> exceptionPrefixes;
+
+ NeverMergeGroup(List<T> prefixes, List<T> exceptionPrefixes) {
+ this.prefixes = prefixes;
+ this.exceptionPrefixes = exceptionPrefixes;
+ }
+
+ public List<T> getPrefixes() {
+ return prefixes;
+ }
+
+ public List<T> getExceptionPrefixes() {
+ return exceptionPrefixes;
+ }
+
+ public <R> NeverMergeGroup<R> map(Function<T, R> fn) {
+ return new NeverMergeGroup<>(
+ prefixes.stream().map(fn).collect(Collectors.toList()),
+ exceptionPrefixes.stream().map(fn).collect(Collectors.toList()));
+ }
+ }
+
// Flag to toggle if the prefix based merge restriction should be enforced.
public boolean enableNeverMergePrefixes = true;
- public Set<String> neverMergePrefixes = ImmutableSet.of("j$.");
+ public NeverMergeGroup<String> neverMerge =
+ new NeverMergeGroup<>(ImmutableList.of("j$."), ImmutableList.of("java."));
public boolean classpathInterfacesMayHaveStaticInitialization = false;
public boolean libraryInterfacesMayHaveStaticInitialization = false;
@@ -1135,23 +1159,6 @@
}
}
- private final Box<Boolean> reportedExperimentClassFileVersion = new Box<>(false);
-
- public void warningExperimentalClassFileVersion(Origin origin) {
- synchronized (reportedExperimentClassFileVersion) {
- if (reportedExperimentClassFileVersion.get()) {
- return;
- }
- reportedExperimentClassFileVersion.set(true);
- reporter.warning(
- new ExperimentalClassFileVersionDiagnostic(
- origin,
- "One or more classes has class file version >= "
- + EXPERIMENTAL_CF_VERSION.major()
- + " which is not officially supported."));
- }
- }
-
public boolean printWarnings() {
boolean printed = false;
boolean printOutdatedToolchain = false;
@@ -1722,10 +1729,6 @@
}
}
- public static void allowExperimentClassFileVersion(InternalOptions options) {
- options.reportedExperimentClassFileVersion.set(true);
- }
-
public static int NO_LIMIT = -1;
public ArgumentPropagatorEventConsumer argumentPropagatorEventConsumer =
diff --git a/src/test/java/com/android/tools/r8/L8TestBuilder.java b/src/test/java/com/android/tools/r8/L8TestBuilder.java
index 7a42ab1..2ff60ba 100644
--- a/src/test/java/com/android/tools/r8/L8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/L8TestBuilder.java
@@ -184,7 +184,10 @@
.inspect(
inspector ->
inspector.forAllClasses(
- clazz -> assertTrue(clazz.getFinalName().startsWith("j$."))));
+ clazz ->
+ assertTrue(
+ clazz.getFinalName().startsWith("j$.")
+ || clazz.getFinalName().startsWith("java."))));
}
private Collection<Path> getProgramFiles() {
diff --git a/src/test/java/com/android/tools/r8/R8CommandTest.java b/src/test/java/com/android/tools/r8/R8CommandTest.java
index d076ec0..1242d17 100644
--- a/src/test/java/com/android/tools/r8/R8CommandTest.java
+++ b/src/test/java/com/android/tools/r8/R8CommandTest.java
@@ -86,6 +86,7 @@
assertTrue(command.getEnableTreeShaking());
assertEquals(CompilationMode.RELEASE, command.getMode());
assertTrue(command.getProgramConsumer() instanceof DexIndexedConsumer);
+ assertFalse(command.getProguardCompatibility());
}
@Test(expected = CompilationFailedException.class)
@@ -268,6 +269,12 @@
}
@Test
+ public void proguardCompatMode() throws Throwable {
+ assertFalse(parse("").getProguardCompatibility());
+ assertTrue(parse("--pg-compat").getProguardCompatibility());
+ }
+
+ @Test
public void classFileOutputModeOption() throws Throwable {
assertTrue(parse("--classfile").getProgramConsumer() instanceof ClassFileConsumer);
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 4daa6a9..3a482a5 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -416,7 +416,7 @@
}
public static TestParametersBuilder getTestParameters() {
- return TestParametersBuilder.builder();
+ return TestParameters.builder();
}
public static KotlinTestParameters.Builder getKotlinTestParameters() {
diff --git a/src/test/java/com/android/tools/r8/TestParameters.java b/src/test/java/com/android/tools/r8/TestParameters.java
index a9b67e3..7853170 100644
--- a/src/test/java/com/android/tools/r8/TestParameters.java
+++ b/src/test/java/com/android/tools/r8/TestParameters.java
@@ -31,6 +31,14 @@
this.apiLevel = apiLevel;
}
+ public static TestParametersBuilder builder() {
+ return new TestParametersBuilder();
+ }
+
+ public static TestParametersCollection justNoneRuntime() {
+ return builder().withNoneRuntime().build();
+ }
+
public boolean canUseDefaultAndStaticInterfaceMethods() {
assert isCfRuntime() || isDexRuntime();
assert !isCfRuntime() || apiLevel == null
diff --git a/src/test/java/com/android/tools/r8/TestParametersBuilder.java b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
index 375f6f8..cb24356 100644
--- a/src/test/java/com/android/tools/r8/TestParametersBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
@@ -26,11 +26,7 @@
private Predicate<TestParameters> filter = param -> false;
private boolean hasDexRuntimeFilter = false;
- private TestParametersBuilder() {}
-
- public static TestParametersBuilder builder() {
- return new TestParametersBuilder();
- }
+ TestParametersBuilder() {}
private TestParametersBuilder withFilter(Predicate<TestParameters> predicate) {
filter = filter.or(predicate);
diff --git a/src/test/java/com/android/tools/r8/TestRuntime.java b/src/test/java/com/android/tools/r8/TestRuntime.java
index 336ffd1..ec3d29c 100644
--- a/src/test/java/com/android/tools/r8/TestRuntime.java
+++ b/src/test/java/com/android/tools/r8/TestRuntime.java
@@ -189,7 +189,7 @@
if (version.startsWith("9.")) {
return new CfRuntime(CfVm.JDK9, Paths.get(home));
}
- if (version.startsWith("11.")) {
+ if (version.equals("11") || version.startsWith("11.")) {
return new CfRuntime(CfVm.JDK11, Paths.get(home));
}
throw new Unimplemented("No support for JDK version: " + version);
diff --git a/src/test/java/com/android/tools/r8/bisect/BisectTest.java b/src/test/java/com/android/tools/r8/bisect/BisectTest.java
index bd1d3c4..3b34747 100644
--- a/src/test/java/com/android/tools/r8/bisect/BisectTest.java
+++ b/src/test/java/com/android/tools/r8/bisect/BisectTest.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.bisect.BisectOptions.Result;
import com.android.tools.r8.dex.ApplicationReader;
@@ -34,7 +33,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection parameters() {
- return TestParametersBuilder.builder().withNoneRuntime().build();
+ return TestParameters.builder().withNoneRuntime().build();
}
public BisectTest(TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapTest.java b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapTest.java
index 14fff26..8c70d15 100644
--- a/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapTest.java
+++ b/src/test/java/com/android/tools/r8/cf/bootstrap/BootstrapTest.java
@@ -3,24 +3,22 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.cf.bootstrap;
-import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import com.android.tools.r8.ClassFileConsumer;
import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.R8Command;
+import com.android.tools.r8.R8;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
-import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.FileUtils;
+import com.android.tools.r8.utils.StringUtils;
import com.google.common.base.Charsets;
-import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Collections;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -29,18 +27,10 @@
@RunWith(Parameterized.class)
public class BootstrapTest extends TestBase {
- private static final Path R8_STABLE_JAR = Paths.get("third_party/r8/r8.jar");
+ private static final Path R8_STABLE_JAR =
+ Paths.get("third_party", "r8-releases", "3.2.54", "r8.jar");
- private static final String R8_NAME = "com.android.tools.r8.R8";
- private static final String[] KEEP_R8 = {
- "-keep public class " + R8_NAME + " {", " public static void main(...);", "}",
- };
- private static final Path DONTWARN_R8 = Paths.get("src/main/dontwarn.txt");
-
- private static final String HELLO_NAME = "hello.Hello";
- private static final String[] KEEP_HELLO = {
- "-keep class " + HELLO_NAME + " {", " public static void main(...);", "}",
- };
+ private static final String HELLO_EXPECTED = StringUtils.lines("Hello World!");
private static class R8Result {
@@ -65,98 +55,112 @@
return getTestParameters().withNoneRuntime().build();
}
+ private static CfRuntime getHostRuntime() {
+ return CfRuntime.getSystemRuntime();
+ }
+
public BootstrapTest(TestParameters parameters) {
- // TODO: use parameters to fork the right Java.
parameters.assertNoneRuntime();
}
+ private Path getHelloInputs() {
+ return ToolHelper.getClassFileForTestClass(Hello.class);
+ }
+
+ private String getHelloKeepRules() {
+ return TestBase.keepMainProguardConfiguration(Hello.class);
+ }
+
@Test
- public void test() throws Exception {
- // Run hello.jar to ensure it exists and is valid.
- Path hello = Paths.get(ToolHelper.EXAMPLES_BUILD_DIR, "hello" + JAR_EXTENSION);
- ProcessResult runHello = ToolHelper.runJava(hello, "hello.Hello");
- assertEquals(0, runHello.exitCode);
+ public void reference() throws Exception {
+ testForJvm()
+ .addProgramFiles(getHelloInputs())
+ .run(getHostRuntime(), Hello.class)
+ .assertSuccessWithOutput(HELLO_EXPECTED);
+ }
+ @Test
+ public void testDebug() throws Exception {
+ compareForMode(CompilationMode.DEBUG);
+ }
+
+ @Test
+ public void testRelease() throws Exception {
+ compareForMode(CompilationMode.RELEASE);
+ }
+
+ private R8Result compareForMode(CompilationMode mode) throws Exception {
// Run r8.jar on hello.jar to ensure that r8.jar is a working compiler.
- R8Result runInputR8 = runExternalR8(R8_STABLE_JAR, hello, "input", KEEP_HELLO, "--debug");
- ProcessResult runHelloR8 = ToolHelper.runJava(runInputR8.outputJar, "hello.Hello");
- assertEquals(runHello.toString(), runHelloR8.toString());
+ R8Result helloCompiledWithR8 =
+ runExternalR8(R8_STABLE_JAR, getHelloInputs(), getHelloKeepRules(), mode);
+ testForJvm()
+ .addProgramFiles(helloCompiledWithR8.outputJar)
+ .run(getHostRuntime(), Hello.class)
+ .assertSuccessWithOutput(HELLO_EXPECTED);
- compareR8(hello, runInputR8, CompilationMode.RELEASE, "r8-r8-rel", "--release", "output-rel");
- compareR8(hello, runInputR8, CompilationMode.DEBUG, "r8-r8", "--debug", "output");
+ compareR8(helloCompiledWithR8, mode);
+ return helloCompiledWithR8;
}
- private void compareR8(
- Path hello,
- R8Result runInputR8,
- CompilationMode internalMode,
- String internalOutput,
- String externalMode,
- String externalOutput)
- throws Exception {
+ private void compareR8(R8Result referenceCompilation, CompilationMode mode) throws Exception {
// Run R8 on r8.jar.
- Path output = runR8(internalOutput, internalMode);
+ Path r8CompiledByR8 = compileR8WithR8(mode);
// Run the resulting compiler on hello.jar.
- R8Result runR8R8 = runExternalR8(output, hello, externalOutput, KEEP_HELLO, externalMode);
+ R8Result runR8R8 = runExternalR8(r8CompiledByR8, getHelloInputs(), getHelloKeepRules(), mode);
// Check that the process outputs (exit code, stdout, stderr) are the same.
- assertEquals(runInputR8.toString(), runR8R8.toString());
+ assertEquals(referenceCompilation.toString(), runR8R8.toString());
// Check that the output jars are the same.
- if (true) {
- // TODO(b/223770583): These should be equal but an error in assertProgramEquals was hiding it.
- assertFalse(filesAreEqual(runInputR8.outputJar, runR8R8.outputJar));
- } else {
- assertProgramsEqual(runInputR8.outputJar, runR8R8.outputJar);
- }
+ assertProgramsEqual(referenceCompilation.outputJar, runR8R8.outputJar);
}
- private Path runR8(String outputFolder, CompilationMode mode) throws Exception {
- Path outputPath = temp.newFolder(outputFolder).toPath();
- Path outputJar = outputPath.resolve("output.jar");
- Path pgConfigFile = outputPath.resolve("keep.rules");
- FileUtils.writeTextFile(pgConfigFile, BootstrapTest.KEEP_R8);
- ToolHelper.runR8(
- R8Command.builder()
- .setMode(mode)
- .addLibraryFiles(ToolHelper.getJava8RuntimeJar())
- .setProgramConsumer(new ClassFileConsumer.ArchiveConsumer(outputJar, true))
- .addProgramFiles(R8_STABLE_JAR)
- .addProguardConfigurationFiles(pgConfigFile, DONTWARN_R8)
- // The R8_STABLE_JAR is from when Guava 23.0 was used, and that included
- // javax.annotation.Nullable annotations in the retained code.
- .addProguardConfiguration(
- ImmutableList.of("-dontwarn javax.annotation.Nullable"), Origin.unknown())
- .build());
- return outputJar;
+ private Path compileR8WithR8(CompilationMode mode) throws Exception {
+ return testForR8(Backend.CF)
+ .setMode(mode)
+ .addProgramFiles(R8_STABLE_JAR)
+ .addKeepRules(TestBase.keepMainProguardConfiguration(R8.class))
+ // The r8 stable/release hits open interface issues.
+ .addOptionsModification(o -> o.getOpenClosedInterfacesOptions().suppressAllOpenInterfaces())
+ // The r8 stable/release contains missing com.google.errorprone annotation references.
+ .addDontWarnGoogle()
+ .compile()
+ .writeToZip();
}
- private R8Result runExternalR8(
- Path r8Jar, Path inputJar, String outputFolder, String[] keepRules, String mode)
+ private R8Result runExternalR8(Path r8Jar, Path inputJar, String keepRules, CompilationMode mode)
throws Exception {
- Path outputPath = temp.newFolder(outputFolder).toPath();
+ Path outputPath = temp.newFolder().toPath();
Path pgConfigFile = outputPath.resolve("keep.rules");
Path outputJar = outputPath.resolve("output.jar");
Path pgMapFile = outputPath.resolve("map.txt");
FileUtils.writeTextFile(pgConfigFile, keepRules);
ProcessResult processResult =
ToolHelper.runJava(
- r8Jar,
- R8_NAME,
+ getHostRuntime(),
+ Collections.singletonList(r8Jar),
+ R8.class.getTypeName(),
"--lib",
- ToolHelper.JAVA_8_RUNTIME,
+ ToolHelper.getJava8RuntimeJar().toString(),
"--classfile",
inputJar.toString(),
"--output",
outputJar.toString(),
"--pg-conf",
pgConfigFile.toString(),
- mode,
+ mode == CompilationMode.DEBUG ? "--debug" : "--release",
"--pg-map-output",
pgMapFile.toString());
if (processResult.exitCode != 0) {
System.out.println(processResult);
}
- assertEquals(processResult.stderr, 0, processResult.exitCode);
+ assertEquals(processResult.toString(), 0, processResult.exitCode);
String pgMap = FileUtils.readTextFile(pgMapFile, Charsets.UTF_8);
return new R8Result(processResult, outputJar, pgMap);
}
+
+ public static class Hello {
+
+ public static void main(String[] args) {
+ System.out.println("Hello World!");
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupLambdaTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupLambdaTest.java
index 7081080..a136180 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/interfaces/CollisionWithDefaultMethodOutsideMergeGroupLambdaTest.java
@@ -18,8 +18,8 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import com.android.tools.r8.utils.codeinspector.HorizontallyMergedClassesInspector;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -46,7 +46,13 @@
// I and J are not eligible for merging, since the lambda that implements I & J inherits a
// default m() method from K, which is also on J.
.addHorizontallyMergedClassesInspector(
- HorizontallyMergedClassesInspector::assertNoClassesMerged)
+ inspector -> {
+ if (parameters.isCfRuntime()) {
+ inspector.assertIsCompleteMergeGroup(I.class, J.class);
+ } else {
+ inspector.assertNoClassesMerged();
+ }
+ })
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoHorizontalClassMergingAnnotations()
@@ -60,13 +66,26 @@
ClassSubject aClassSubject = inspector.clazz(A.class);
if (parameters.canUseDefaultAndStaticInterfaceMethods()) {
assertThat(aClassSubject, isPresent());
- assertThat(aClassSubject, isImplementing(inspector.clazz(J.class)));
+ if (parameters.isCfRuntime()) {
+ assertThat(aClassSubject, isImplementing(inspector.clazz(I.class)));
+ } else {
+ assertThat(aClassSubject, isImplementing(inspector.clazz(J.class)));
+ }
} else {
assertThat(aClassSubject, isAbsent());
}
})
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("K", "J");
+ // TODO(b/173990042): Should succeed with "K", "J".
+ .applyIf(
+ parameters.isCfRuntime(),
+ builder ->
+ builder.assertFailureWithErrorThatThrows(
+ parameters.isCfRuntime()
+ && parameters.getRuntime().asCf().isNewerThanOrEqual(CfVm.JDK11)
+ ? AbstractMethodError.class
+ : IncompatibleClassChangeError.class),
+ builder -> builder.assertSuccessWithOutputLines("K", "J"));
}
static class Main {
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
index ebba822..2c3a478 100644
--- a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
+++ b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.AndroidApiLevel;
import java.util.List;
@@ -31,7 +30,7 @@
@Parameters(name = "{0}, kotlinc: {1}")
public static List<Object[]> setup() {
return buildParameters(
- TestParametersBuilder.builder().withAllRuntimesAndApiLevels().build(),
+ TestParameters.builder().withAllRuntimesAndApiLevels().build(),
getKotlinTestParameters().withAllCompilers().withNoTargetVersion().build());
}
diff --git a/src/test/java/com/android/tools/r8/debug/LineNumberOptimizationTest.java b/src/test/java/com/android/tools/r8/debug/LineNumberOptimizationTest.java
index d227ea3..af193de 100644
--- a/src/test/java/com/android/tools/r8/debug/LineNumberOptimizationTest.java
+++ b/src/test/java/com/android/tools/r8/debug/LineNumberOptimizationTest.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.InternalOptions.LineNumberOptimization;
import org.junit.Test;
@@ -34,7 +33,7 @@
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection setup() {
- return TestParametersBuilder.builder().withAllRuntimesAndApiLevels().build();
+ return TestParameters.builder().withAllRuntimesAndApiLevels().build();
}
public LineNumberOptimizationTest(TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/debuginfo/DebugSetFileSmaliTest.java b/src/test/java/com/android/tools/r8/debuginfo/DebugSetFileSmaliTest.java
index 008d3cf..416cada 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/DebugSetFileSmaliTest.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/DebugSetFileSmaliTest.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.graph.DexDebugEvent.SetFile;
import com.android.tools.r8.smali.SmaliBuilder;
@@ -30,10 +29,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection parameters() {
- return TestParametersBuilder.builder()
- .withDexRuntimes()
- .withApiLevel(AndroidApiLevel.B)
- .build();
+ return TestParameters.builder().withDexRuntimes().withApiLevel(AndroidApiLevel.B).build();
}
private static final String CLASS_NAME = "Test";
diff --git a/src/test/java/com/android/tools/r8/debuginfo/InliningWithoutPositionsTestRunner.java b/src/test/java/com/android/tools/r8/debuginfo/InliningWithoutPositionsTestRunner.java
index b683d7d..6af4440 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/InliningWithoutPositionsTestRunner.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/InliningWithoutPositionsTestRunner.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.debuginfo.InliningWithoutPositionsTestSourceDump.Location;
import com.android.tools.r8.naming.retrace.StackTrace;
import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
@@ -44,7 +43,7 @@
public static Collection<Object[]> data() {
List<Object[]> testCases = new ArrayList<>();
for (TestParameters parameters :
- TestParametersBuilder.builder().withAllRuntimes().withApiLevel(AndroidApiLevel.B).build()) {
+ TestParameters.builder().withAllRuntimes().withApiLevel(AndroidApiLevel.B).build()) {
for (int i = 0; i < 16; ++i) {
for (Location throwLocation : Location.values()) {
if (throwLocation != Location.MAIN) {
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileB156591935.java b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileB156591935.java
index 674f288..e288d12 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileB156591935.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileB156591935.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -29,7 +28,7 @@
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
- return TestParametersBuilder.builder().withCfRuntimes().withAllApiLevelsAlsoForCf().build();
+ return TestParameters.builder().withCfRuntimes().withAllApiLevelsAlsoForCf().build();
}
private final AndroidApiLevel apiLevel;
diff --git a/src/test/java/com/android/tools/r8/desugar/InterfaceInvokePrivateTest.java b/src/test/java/com/android/tools/r8/desugar/InterfaceInvokePrivateTest.java
index 86c5440..1d88df8 100644
--- a/src/test/java/com/android/tools/r8/desugar/InterfaceInvokePrivateTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/InterfaceInvokePrivateTest.java
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.desugar;
-import static com.android.tools.r8.utils.InternalOptions.EXPERIMENTAL_CF_VERSION;
import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assume.assumeTrue;
@@ -106,8 +105,6 @@
// TODO(b/185463156): Not keeping I and its members will "fix" the ICCE for all runtimes.
.addKeepClassAndMembersRules(I.class)
.setMinApi(parameters.getApiLevel())
- .allowDiagnosticWarningMessages(
- inputCfVersion.isGreaterThanOrEqualTo(EXPERIMENTAL_CF_VERSION))
.compile()
.run(parameters.getRuntime(), TestRunner.class)
.applyIf(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
index f79b585..93ea904 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/BufferedReaderTest.java
@@ -51,13 +51,7 @@
}
private String expectedOutput() {
- return StringUtils.lines(
- "Hello",
- "Larry",
- "Page",
- parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)
- ? "Caught java.io.UncheckedIOException"
- : "Caught j$.io.UncheckedIOException");
+ return StringUtils.lines("Hello", "Larry", "Page", "Caught java.io.UncheckedIOException");
}
DesugaredLibrarySpecification configurationAlternative3(
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocalDateEpochTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocalDateEpochTest.java
new file mode 100644
index 0000000..23a146e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/LocalDateEpochTest.java
@@ -0,0 +1,132 @@
+// 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 com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.FieldAccessFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.DesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanDesugaredLibrarySpecification;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanRewritingFlags;
+import com.android.tools.r8.ir.desugar.desugaredlibrary.humanspecification.HumanTopLevelFlags;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.transformers.MethodTransformer;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.collect.ImmutableList;
+import java.io.IOException;
+import java.time.LocalDate;
+import java.util.Collection;
+import org.junit.Assume;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class LocalDateEpochTest extends DesugaredLibraryTestBase {
+
+ private final TestParameters parameters;
+
+ private static final String EXPECTED_OUTPUT = StringUtils.lines("1970-01-01");
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ .withDexRuntimesStartingFromIncluding(Version.V8_1_0)
+ .withAllApiLevels()
+ .build();
+ }
+
+ public LocalDateEpochTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ testForD8(parameters.getBackend())
+ .addLibraryFiles(getLibraryFile())
+ .addProgramClasses(DesugarLocalDate.class)
+ .addProgramClassFileData(getMainClassFileData())
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(opt -> opt.setDesugaredLibrarySpecification(getSpecification(opt)))
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ Assume.assumeTrue(parameters.isDexRuntime());
+ testForR8(parameters.getBackend())
+ .addLibraryFiles(getLibraryFile())
+ .addProgramClasses(DesugarLocalDate.class)
+ .addProgramClassFileData(getMainClassFileData())
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .addOptionsModification(opt -> opt.setDesugaredLibrarySpecification(getSpecification(opt)))
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT);
+ }
+
+ private DesugaredLibrarySpecification getSpecification(InternalOptions options) {
+ DexType date = options.dexItemFactory().createType("Ljava/time/LocalDate;");
+ DexType desugarDate =
+ options
+ .dexItemFactory()
+ .createType("L" + DescriptorUtils.getClassBinaryName(DesugarLocalDate.class) + ";");
+ DexString epoch = options.dexItemFactory().createString("EPOCH");
+ DexField src = options.dexItemFactory().createField(date, date, epoch);
+ HumanRewritingFlags rewritingFlags =
+ HumanRewritingFlags.builder(options.reporter, Origin.unknown())
+ .retargetStaticField(src, desugarDate)
+ .amendLibraryField(
+ src,
+ FieldAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_STATIC | Constants.ACC_FINAL))
+ .build();
+ return new HumanDesugaredLibrarySpecification(
+ HumanTopLevelFlags.testing(), rewritingFlags, false);
+ }
+
+ private Collection<byte[]> getMainClassFileData() throws IOException {
+ return ImmutableList.of(
+ transformer(Main.class)
+ .addMethodTransformer(
+ new MethodTransformer() {
+ @Override
+ public void visitFieldInsn(
+ final int opcode,
+ final String owner,
+ final String name,
+ final String descriptor) {
+ if (name.equals("MIN")) {
+ super.visitFieldInsn(opcode, owner, "EPOCH", descriptor);
+ } else {
+ super.visitFieldInsn(opcode, owner, name, descriptor);
+ }
+ }
+ })
+ .transform());
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ System.out.println(LocalDate.MIN);
+ }
+ }
+
+ static class DesugarLocalDate {
+
+ public static final LocalDate EPOCH = LocalDate.of(1970, 1, 1);
+ }
+}
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 1208414..568de28 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
@@ -7,12 +7,14 @@
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertTrue;
+import static org.hamcrest.CoreMatchers.containsString;
import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8Command;
import com.android.tools.r8.DexFileMergerHelper;
+import com.android.tools.r8.DiagnosticsMatcher;
import com.android.tools.r8.L8;
import com.android.tools.r8.L8Command;
import com.android.tools.r8.OutputMode;
@@ -24,8 +26,10 @@
import com.android.tools.r8.errors.DuplicateTypesDiagnostic;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import java.nio.file.Path;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -127,4 +131,134 @@
.build());
return outputDex;
}
+
+ @Test
+ public void testJavaMergesWithEverything() throws Exception {
+ // java and other prefixes can co-exist in same DEX.
+ Path dexWithJavaAndNonJ$Classes =
+ testForD8()
+ .addProgramClassFileData(
+ transformer(A.class).setClassDescriptor("Ljava/A;").transform())
+ .addInnerClasses(getClass())
+ .compile()
+ .writeToZip();
+
+ // Can be merged with other java classes.
+ testForD8()
+ .addProgramFiles(dexWithJavaAndNonJ$Classes)
+ .addProgramFiles(
+ testForD8()
+ .addProgramClassFileData(
+ transformer(B.class).setClassDescriptor("Ljava/B;").transform())
+ .compile()
+ .writeToZip())
+ .compile();
+
+ // Cannot be merged with j$ classes.
+ Path j$Dex =
+ testForD8()
+ .addProgramClassFileData(transformer(A.class).setClassDescriptor("Lj$/A;").transform())
+ .compile()
+ .writeToZip();
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ testForD8()
+ .addProgramFiles(dexWithJavaAndNonJ$Classes)
+ .addProgramFiles(j$Dex)
+ .compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics.assertErrorsMatch(
+ DiagnosticsMatcher.diagnosticMessage(
+ containsString(
+ "Merging DEX file containing classes with prefix")))));
+
+ // Cannot be merged with j$ even if they are together with java.
+ Path j$JavaDex =
+ testForD8()
+ .addProgramClassFileData(transformer(A.class).setClassDescriptor("Lj$/A;").transform())
+ .addProgramClassFileData(
+ transformer(B.class).setClassDescriptor("Ljava/B;").transform())
+ .compile()
+ .writeToZip();
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ testForD8()
+ .addProgramFiles(dexWithJavaAndNonJ$Classes)
+ .addProgramFiles(j$JavaDex)
+ .compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics.assertErrorsMatch(
+ DiagnosticsMatcher.diagnosticMessage(
+ containsString(
+ "Merging DEX file containing classes with prefix")))));
+ }
+
+ @Test
+ public void testJ$OnlyMergesWithJava() throws Exception {
+ Path j$Dex =
+ testForD8()
+ .addProgramClassFileData(transformer(A.class).setClassDescriptor("Lj$/A;").transform())
+ .compile()
+ .writeToZip();
+ Path javaDex =
+ testForD8()
+ .addProgramClassFileData(
+ transformer(A.class).setClassDescriptor("Ljava/A;").transform())
+ .compile()
+ .writeToZip();
+ Path j$Dex2 =
+ testForD8()
+ .addProgramClassFileData(transformer(B.class).setClassDescriptor("Lj$/B;").transform())
+ .compile()
+ .writeToZip();
+ Path javaDex2 =
+ testForD8()
+ .addProgramClassFileData(
+ transformer(B.class).setClassDescriptor("Ljava/B;").transform())
+ .compile()
+ .writeToZip();
+ Path javaJ$Dex =
+ testForD8()
+ .addProgramClassFileData(transformer(C.class).setClassDescriptor("Lj$/C;").transform())
+ .addProgramClassFileData(
+ transformer(C.class).setClassDescriptor("Ljava/C;").transform())
+ .compile()
+ .writeToZip();
+
+ List<Path> j$Dexes = ImmutableList.of(j$Dex, j$Dex2, javaJ$Dex);
+ List<Path> allDexes = ImmutableList.of(j$Dex, javaDex, j$Dex2, javaDex2, javaJ$Dex);
+ testForD8().addProgramFiles(allDexes).compile();
+
+ for (Path first : allDexes) {
+ for (Path second : allDexes) {
+ if (first != second) {
+ testForD8().addProgramFiles(first, second).compile();
+ }
+ }
+ if (j$Dexes.contains(first)) {
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ testForD8()
+ .addInnerClasses(getClass())
+ .addProgramFiles(first)
+ .compileWithExpectedDiagnostics(
+ diagnostics ->
+ diagnostics.assertErrorsMatch(
+ DiagnosticsMatcher.diagnosticMessage(
+ containsString(
+ "Merging DEX file containing classes with prefix")))));
+ } else {
+ testForD8().addInnerClasses(getClass()).addProgramFiles(first).compile();
+ }
+ }
+ }
+
+ static class A {}
+
+ static class B {}
+
+ static class C {}
}
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 8a86def..607ff9b 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
@@ -52,8 +52,9 @@
assertThat(
message,
containsString(
- "Merging dex file containing classes with prefix 'j$.' "
- + "with classes with any other prefixes is not allowed"));
+ "Merging DEX file containing classes with prefix 'j$.' "
+ + "with other classes, except classes with prefix 'java.', "
+ + "is not allowed:"));
});
} catch (CompilationFailedException e) {
// Expected compilation failed.
@@ -78,8 +79,9 @@
assertThat(
message,
containsString(
- "Merging dex file containing classes with prefix 'j$.' "
- + "with classes with any other prefixes is not allowed"));
+ "Merging DEX file containing classes with prefix 'j$.' "
+ + "with other classes, except classes with prefix 'java.', "
+ + "is not allowed:"));
});
} catch (CompilationFailedException e) {
// Expected compilation failed.
diff --git a/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java b/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
index 13e021d..15473c5 100644
--- a/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/jdk8272564/Jdk8272564Test.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.examples.jdk18.jdk8272564.Jdk8272564;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import org.junit.Test;
@@ -160,7 +159,6 @@
.setMinApi(parameters.getApiLevel())
.noTreeShaking()
.addKeepClassAndMembersRules(Jdk8272564.Main.typeName())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.run(parameters.getRuntime(), Jdk8272564.Main.typeName())
.inspect(this::assertJdk8272564NotFixedCodeR8)
.assertSuccess();
diff --git a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java
index 1624c29..8de3689 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordAnnotationTest.java
@@ -4,7 +4,6 @@
package com.android.tools.r8.desugar.records;
-import static com.android.tools.r8.utils.InternalOptions.TestingOptions;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.R8FullTestBuilder;
@@ -61,7 +60,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT_DEX);
@@ -77,8 +75,7 @@
.addKeepRules("-keep class records.EmptyRecordAnnotation { *; }")
.addKeepRules("-keepattributes *Annotation*")
.addKeepRules("-keep class records.EmptyRecordAnnotation$Empty")
- .addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion);
+ .addKeepMainRule(MAIN_TYPE);
if (parameters.isCfRuntime()) {
builder
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
diff --git a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
index 5f1b68f..3e44232 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/EmptyRecordTest.java
@@ -4,8 +4,6 @@
package com.android.tools.r8.desugar.records;
-import static com.android.tools.r8.utils.InternalOptions.TestingOptions;
-
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -52,7 +50,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT_D8);
@@ -64,8 +61,7 @@
testForR8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion);
+ .addKeepMainRule(MAIN_TYPE);
if (parameters.isCfRuntime()) {
builder
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
index 743b2b4..f0d89d6 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInstanceOfTest.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
import org.junit.Test;
@@ -50,7 +49,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT);
@@ -62,8 +60,7 @@
testForR8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion);
+ .addKeepMainRule(MAIN_TYPE);
if (parameters.isCfRuntime()) {
builder
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
index 9ee21d2..f6c39e6 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomSplitDesugaringTest.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
import java.util.List;
@@ -56,13 +55,11 @@
testForD8(Backend.CF)
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.writeToZip();
testForD8(parameters.getBackend())
.addProgramFiles(desugared)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT_D8);
@@ -74,14 +71,12 @@
testForD8(Backend.CF)
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.writeToZip();
testForR8(parameters.getBackend())
.addProgramFiles(desugared)
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT_R8);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
index 61ee05b..b851c88 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordInvokeCustomTest.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
import org.junit.Test;
@@ -67,7 +66,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT_D8);
@@ -79,8 +77,7 @@
testForR8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion);
+ .addKeepMainRule(MAIN_TYPE);
if (parameters.isCfRuntime()) {
builder
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordKeepRulesTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordKeepRulesTest.java
index 49df3e2..f34bd67 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordKeepRulesTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordKeepRulesTest.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
import java.util.List;
@@ -87,7 +86,6 @@
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_TYPE)
.addKeepRules(keepRules)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(expectedOutput);
}
@@ -100,13 +98,11 @@
.addKeepMainRule(MAIN_TYPE)
.addKeepRules(keepRules)
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.writeToZip();
testForD8(parameters.getBackend())
.addProgramFiles(desugared)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(expectedOutput);
}
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java
index 53eff63..1701934 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordLibMergeTest.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
import java.util.List;
@@ -52,7 +51,6 @@
"-keep class records.RecordLib { public static java.lang.Object getRecord(); }")
.addKeepRules("-keep class records.RecordLib$LibRecord")
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.writeToZip();
R8FullTestBuilder builder =
@@ -62,8 +60,7 @@
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_TYPE)
.addKeepRules("-keep class records.RecordLib$LibRecord")
- .addKeepRules("-keep class records.RecordMain$MainRecord")
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion);
+ .addKeepRules("-keep class records.RecordMain$MainRecord");
if (parameters.isCfRuntime()) {
builder
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
index cf3c955..d3816f8 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordMergeTest.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.errors.DuplicateTypesDiagnostic;
import com.android.tools.r8.errors.MissingGlobalSyntheticsConsumerDiagnostic;
import com.android.tools.r8.synthesis.globals.GlobalSyntheticsConsumerAndProvider;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.nio.file.Path;
@@ -62,7 +61,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA_1)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.setIntermediate(true)
.compileWithExpectedDiagnostics(
diagnostics ->
@@ -79,7 +77,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA_1)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.setIntermediate(true)
.apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(globals1))
.compile()
@@ -91,7 +88,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA_2)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.setIntermediate(true)
.apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(globals2))
.compile()
@@ -106,7 +102,6 @@
.addProgramFiles(output1, output2)
.apply(b -> b.getBuilder().addGlobalSyntheticsResourceProviders(globals1, globals2))
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.inspect(this::assertHasRecordTag);
@@ -121,7 +116,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA_1)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.setIntermediate(true)
.apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(globals1))
.compile()
@@ -133,7 +127,6 @@
.apply(b -> b.getBuilder().addGlobalSyntheticsResourceProviders(globals1))
.addProgramClassFileData(PROGRAM_DATA_2)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile();
result.run(parameters.getRuntime(), MAIN_TYPE_1).assertSuccessWithOutput(EXPECTED_RESULT_1);
result.run(parameters.getRuntime(), MAIN_TYPE_2).assertSuccessWithOutput(EXPECTED_RESULT_2);
@@ -145,7 +138,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA_1)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.inspect(this::assertHasRecordTag)
.writeToZip();
@@ -154,7 +146,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA_2)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.inspect(this::assertHasRecordTag)
.writeToZip();
@@ -165,7 +156,6 @@
testForD8(parameters.getBackend())
.addProgramFiles(output1, output2)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compileWithExpectedDiagnostics(
diagnostics ->
diagnostics
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
index 7b1096d..1bdc08d 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordReflectionTest.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
import org.junit.Test;
@@ -61,7 +60,6 @@
.addKeepRules("-keepattributes *")
.addKeepRules("-keep class * extends java.lang.Record { private final <fields>; }")
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.inspect(RecordTestUtils::assertRecordsAreRecords)
.enableJVMPreview()
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordShrinkFieldTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordShrinkFieldTest.java
index 8dc4a82..2c426fc 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordShrinkFieldTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordShrinkFieldTest.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -47,7 +46,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT_D8);
@@ -59,7 +57,6 @@
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.inspect(this::assertSingleField)
.run(parameters.getRuntime(), MAIN_TYPE)
@@ -74,14 +71,12 @@
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_TYPE)
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.writeToZip();
testForR8(parameters.getBackend())
.addProgramFiles(desugared)
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.inspect(this::assertSingleField)
.run(parameters.getRuntime(), MAIN_TYPE)
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
index eb8ef2d..07ae7cb 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordWithMembersTest.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.util.List;
import org.junit.Test;
@@ -52,7 +51,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT);
@@ -64,8 +62,7 @@
testForR8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion);
+ .addKeepMainRule(MAIN_TYPE);
if (parameters.isCfRuntime()) {
builder
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordWithNonMaterializableConstClassTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordWithNonMaterializableConstClassTest.java
index f76b137..7ee039f 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/RecordWithNonMaterializableConstClassTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordWithNonMaterializableConstClassTest.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
import java.util.List;
@@ -56,7 +55,6 @@
.addProgramClassFileData(PROGRAM_DATA)
.addProgramClassFileData(EXTRA_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT_D8);
@@ -70,7 +68,6 @@
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_TYPE)
.addKeepRules("-keep class " + PRIVATE_CLASS_NAME)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT_R8);
@@ -86,7 +83,6 @@
.addKeepMainRule(MAIN_TYPE)
.addKeepRules("-keep class " + PRIVATE_CLASS_NAME)
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.writeToZip();
testForR8(parameters.getBackend())
@@ -94,7 +90,6 @@
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_TYPE)
.addKeepRules("-keep class " + PRIVATE_CLASS_NAME)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT_R8);
diff --git a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
index 212098c..e94b6b6 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/SimpleRecordTest.java
@@ -10,11 +10,9 @@
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.synthesis.globals.GlobalSyntheticsConsumerAndProvider;
import com.android.tools.r8.utils.AndroidApiLevel;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
import java.util.List;
@@ -66,7 +64,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.inspectWithOptions(
RecordTestUtils::assertNoJavaLangRecord,
@@ -110,7 +107,6 @@
return testForD8(Backend.DEX)
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.setIntermediate(true)
.setIncludeClassesChecksum(true)
.apply(b -> b.getBuilder().setGlobalSyntheticsConsumer(globalSyntheticsConsumer))
@@ -125,8 +121,7 @@
testForR8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion);
+ .addKeepMainRule(MAIN_TYPE);
if (parameters.isCfRuntime()) {
builder
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
@@ -153,8 +148,7 @@
.addProgramClassFileData(PROGRAM_DATA)
.noMinification()
.setMinApi(parameters.getApiLevel())
- .addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion);
+ .addKeepMainRule(MAIN_TYPE);
if (parameters.isCfRuntime()) {
builder
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
diff --git a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordFieldTest.java b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordFieldTest.java
index 24ae5d7..bd59f23 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordFieldTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordFieldTest.java
@@ -4,8 +4,6 @@
package com.android.tools.r8.desugar.records;
-import static com.android.tools.r8.utils.InternalOptions.TestingOptions;
-
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -51,7 +49,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT);
@@ -64,8 +61,7 @@
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
.addKeepRules("-keep class records.UnusedRecordField { *; }")
- .addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion);
+ .addKeepMainRule(MAIN_TYPE);
if (parameters.isCfRuntime()) {
builder
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
diff --git a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordMethodTest.java b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordMethodTest.java
index 702cc75..70ed745 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordMethodTest.java
@@ -4,8 +4,6 @@
package com.android.tools.r8.desugar.records;
-import static com.android.tools.r8.utils.InternalOptions.TestingOptions;
-
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -51,7 +49,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT);
@@ -64,8 +61,7 @@
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
.addKeepRules("-keep class records.UnusedRecordMethod { *; }")
- .addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion);
+ .addKeepMainRule(MAIN_TYPE);
if (parameters.isCfRuntime()) {
builder
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
diff --git a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordReflectionTest.java b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordReflectionTest.java
index 0687934..066c68b 100644
--- a/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordReflectionTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/records/UnusedRecordReflectionTest.java
@@ -4,8 +4,6 @@
package com.android.tools.r8.desugar.records;
-import static com.android.tools.r8.utils.InternalOptions.TestingOptions;
-
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -51,7 +49,6 @@
testForD8(parameters.getBackend())
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN_TYPE)
.assertSuccessWithOutput(EXPECTED_RESULT);
@@ -64,8 +61,7 @@
.addProgramClassFileData(PROGRAM_DATA)
.setMinApi(parameters.getApiLevel())
.addKeepRules("-keep class records.UnusedRecordReflection { *; }")
- .addKeepMainRule(MAIN_TYPE)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion);
+ .addKeepMainRule(MAIN_TYPE);
if (parameters.isCfRuntime()) {
builder
.addLibraryFiles(RecordTestUtils.getJdk15LibraryFiles(temp))
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeClasspathTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeClasspathTest.java
index a74132f..facd808 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeClasspathTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeClasspathTest.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.examples.jdk17.Sealed;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,7 +34,6 @@
.addClasspathFiles(Sealed.jar())
.addInnerClasses(getClass())
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.run(parameters.getRuntime(), TestRunner.class)
.assertSuccessWithOutputLines("Hello, world!");
}
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeLibraryTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeLibraryTest.java
index 4eb4bd2..57684f3 100644
--- a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeLibraryTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeLibraryTest.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.TestCompilerBuilder;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.examples.jdk17.Sealed;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -36,7 +35,6 @@
.addLibraryFiles(Sealed.jar())
.addInnerClasses(getClass())
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.run(parameters.getRuntime(), TestRunner.class)
.assertSuccessWithOutputLines("Hello, world!");
}
diff --git a/src/test/java/com/android/tools/r8/examples/abstractmethodremoval/AbstractMethodRemovalTestRunner.java b/src/test/java/com/android/tools/r8/examples/abstractmethodremoval/AbstractMethodRemovalTestRunner.java
index 20cda19..39d93b9 100644
--- a/src/test/java/com/android/tools/r8/examples/abstractmethodremoval/AbstractMethodRemovalTestRunner.java
+++ b/src/test/java/com/android/tools/r8/examples/abstractmethodremoval/AbstractMethodRemovalTestRunner.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.examples.abstractmethodremoval.a.PackageBase;
import com.android.tools.r8.examples.abstractmethodremoval.a.Public;
import com.android.tools.r8.examples.abstractmethodremoval.b.Impl1;
@@ -66,11 +65,6 @@
.addKeepMainRule(getMainClass())
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), getMainClass())
- .applyIf(
- // TODO(b/227302144): The program should not fail after R8.
- parameters.isDexRuntime()
- && parameters.asDexRuntime().getVersion().isNewerThanOrEqual(Version.V5_1_1),
- r -> r.assertFailure(),
- r -> r.assertSuccessWithOutput(getExpected()));
+ .assertSuccessWithOutput(getExpected());
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
index 5162100..1433f2e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/MemberValuePropagationTest.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -38,7 +37,7 @@
@Parameterized.Parameters(name = "Backend: {1}")
public static List<Object[]> data() {
return buildParameters(
- TestParametersBuilder.builder().withNoneRuntime().build(), ToolHelper.getBackends());
+ TestParameters.builder().withNoneRuntime().build(), ToolHelper.getBackends());
}
public MemberValuePropagationTest(TestParameters parameters, TestBase.Backend backend) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceCheckCastTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceCheckCastTest.java
index c756f8c..e8d4e5f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceCheckCastTest.java
@@ -41,7 +41,7 @@
.addProgramClasses(getProgramClasses())
.addProgramClassFileData(getTransformedMainClass())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines());
+ .assertSuccessWithOutputLines(getExpectedOutputLines(false));
}
@Test
@@ -52,7 +52,7 @@
.addProgramClassFileData(getTransformedMainClass())
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines());
+ .assertSuccessWithOutputLines(getExpectedOutputLines(false));
}
@Test
@@ -68,7 +68,7 @@
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines());
+ .assertSuccessWithOutputLines(getExpectedOutputLines(true));
}
private List<Class<?>> getProgramClasses() {
@@ -102,7 +102,11 @@
.transform();
}
- private List<String> getExpectedOutputLines() {
+ private List<String> getExpectedOutputLines(boolean isR8) {
+ if (isR8) {
+ // TODO(b/214496607): R8 should not optimize the check-cast instruction since I is open.
+ return ImmutableList.of("OK", "OK");
+ }
if (parameters.isDexRuntime()
&& parameters
.getDexRuntimeVersion()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInliningTest.java
index 4eaa6a4..e2b4a29 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInliningTest.java
@@ -71,7 +71,8 @@
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines());
+ // TODO(b/214496607): Should succeed with the expected output.
+ .assertFailureWithErrorThatThrows(ClassCastException.class);
}
private List<Class<?>> getProgramClasses() {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInstanceofTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInstanceofTest.java
index dac3848..5a57dc4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInstanceofTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenInterfaceInstanceofTest.java
@@ -41,7 +41,7 @@
.addProgramClasses(getProgramClasses())
.addProgramClassFileData(getTransformedMainClass())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines());
+ .assertSuccessWithOutputLines(getExpectedOutputLines(false));
}
@Test
@@ -52,7 +52,7 @@
.addProgramClassFileData(getTransformedMainClass())
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines());
+ .assertSuccessWithOutputLines(getExpectedOutputLines(false));
}
@Test
@@ -68,7 +68,7 @@
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines());
+ .assertSuccessWithOutputLines(getExpectedOutputLines(true));
}
private List<Class<?>> getProgramClasses() {
@@ -95,7 +95,11 @@
.transform();
}
- private List<String> getExpectedOutputLines() {
+ private List<String> getExpectedOutputLines(boolean isR8) {
+ if (isR8) {
+ // TODO(b/214496607): R8 should not optimize the instanceof instruction since I is open.
+ return ImmutableList.of("true", "true");
+ }
if (parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isEqualTo(Version.V7_0_0)) {
return ImmutableList.of("true", "true");
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java
index 606871f..a729899 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/interfaces/OpenUninstantiatedInterfaceInstanceofTest.java
@@ -40,7 +40,7 @@
.addProgramClasses(getProgramClasses())
.addProgramClassFileData(getTransformedMainClass())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines());
+ .assertSuccessWithOutputLines(getExpectedOutputLines(false));
}
@Test
@@ -51,7 +51,7 @@
.addProgramClassFileData(getTransformedMainClass())
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines());
+ .assertSuccessWithOutputLines(getExpectedOutputLines(false));
}
@Test
@@ -65,7 +65,7 @@
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines(getExpectedOutputLines());
+ .assertSuccessWithOutputLines(getExpectedOutputLines(true));
}
private List<Class<?>> getProgramClasses() {
@@ -92,7 +92,11 @@
.transform();
}
- private List<String> getExpectedOutputLines() {
+ private List<String> getExpectedOutputLines(boolean isR8) {
+ if (isR8) {
+ // TODO(b/214496607): R8 should not optimize the instanceof instruction since I is open.
+ return ImmutableList.of("true");
+ }
if (parameters.isDexRuntime()) {
if (parameters.getDexRuntimeVersion().isEqualTo(Version.V7_0_0)
|| parameters.getDexRuntimeVersion().isEqualTo(Version.V13_MASTER)) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/lambda/LambdaMethodInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/lambda/LambdaMethodInliningTest.java
index a3d1e6b..a63addb 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/lambda/LambdaMethodInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/lambda/LambdaMethodInliningTest.java
@@ -65,7 +65,7 @@
assertTrue(
testClassMethodSubject
.streamInstructions()
- .noneMatch(
+ .anyMatch(
instruction ->
instruction.isInvokeVirtual()
&& instruction.getMethod().toSourceString().contains("println")));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/LambdaInstantiatedTypeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/LambdaInstantiatedTypeTest.java
index 1b3e93e..4d032c7 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/LambdaInstantiatedTypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/LambdaInstantiatedTypeTest.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -30,7 +29,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return TestParametersBuilder.builder().withAllRuntimesAndApiLevels().build();
+ return TestParameters.builder().withAllRuntimesAndApiLevels().build();
}
public LambdaInstantiatedTypeTest(TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsTestBase.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsTestBase.java
index d88a978..822f9f9 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsTestBase.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -36,8 +35,7 @@
@Parameters(name = "{0}, minification:{1}")
public static Collection<Object[]> data() {
return buildParameters(
- TestParametersBuilder.builder().withAllRuntimesAndApiLevels().build(),
- BooleanUtils.values());
+ TestParameters.builder().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
}
public void configure(R8FullTestBuilder builder) {
diff --git a/src/test/java/com/android/tools/r8/jasmin/InvalidClassNames.java b/src/test/java/com/android/tools/r8/jasmin/InvalidClassNames.java
index bd462b7..b8378c3 100644
--- a/src/test/java/com/android/tools/r8/jasmin/InvalidClassNames.java
+++ b/src/test/java/com/android/tools/r8/jasmin/InvalidClassNames.java
@@ -3,8 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.jasmin;
-
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -23,32 +22,19 @@
@Parameters(name = "\"{0}\", jvm: {1}, art: {2}")
public static Collection<Object[]> data() {
Collection<Object[]> data = new ArrayList<>();
- data.addAll(NameTestBase.getCommonNameTestData(true));
- data.addAll(
- Arrays.asList(
- new Object[][] {
- {new TestString("a/b/c/a/D/"), true, false},
- {
- new TestString("a<b"),
- !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime(),
- false
- },
- {
- new TestString("a>b"),
- !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime(),
- false
- },
- {
- new TestString("<a>b"),
- !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime(),
- false
- },
- {
- new TestString("<a>"),
- !ToolHelper.isWindows() && !ToolHelper.isJava9Runtime(),
- false
- }
- }));
+ for (TestParameters parameter : TestParameters.justNoneRuntime()) {
+ parameter.assertNoneRuntime();
+ data.addAll(NameTestBase.getCommonNameTestData());
+ data.addAll(
+ Arrays.asList(
+ new Object[][] {
+ {new TestString("a/b/c/a/D/"), true, false},
+ {new TestString("a<b"), false, false},
+ {new TestString("a>b"), false, false},
+ {new TestString("<a>b"), false, false},
+ {new TestString("<a>"), false, false}
+ }));
+ }
return data;
}
diff --git a/src/test/java/com/android/tools/r8/jasmin/InvalidFieldNames.java b/src/test/java/com/android/tools/r8/jasmin/InvalidFieldNames.java
index 8f680ee..cea2557 100644
--- a/src/test/java/com/android/tools/r8/jasmin/InvalidFieldNames.java
+++ b/src/test/java/com/android/tools/r8/jasmin/InvalidFieldNames.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.jasmin;
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -21,17 +21,20 @@
@Parameters(name = "\"{0}\", jvm: {1}, art: {2}")
public static Collection<Object[]> data() {
Collection<Object[]> data = new ArrayList<>();
- data.addAll(NameTestBase.getCommonNameTestData(false));
- data.addAll(
- Arrays.asList(
- new Object[][] {
- {new TestString("a/b"), false, false},
- {new TestString("<a"), !ToolHelper.isJava9Runtime(), false},
- {new TestString("a>"), !ToolHelper.isJava9Runtime(), false},
- {new TestString("a<b>"), !ToolHelper.isJava9Runtime(), false},
- {new TestString("<a>b"), !ToolHelper.isJava9Runtime(), false},
- {new TestString("<a>"), false, true}
- }));
+ for (TestParameters parameter : TestParameters.justNoneRuntime()) {
+ parameter.assertNoneRuntime();
+ data.addAll(NameTestBase.getCommonNameTestData());
+ data.addAll(
+ Arrays.asList(
+ new Object[][] {
+ {new TestString("a/b"), false, false},
+ {new TestString("<a"), false, false},
+ {new TestString("a>"), false, false},
+ {new TestString("a<b>"), false, false},
+ {new TestString("<a>b"), false, false},
+ {new TestString("<a>"), false, true}
+ }));
+ }
return data;
}
diff --git a/src/test/java/com/android/tools/r8/jasmin/InvalidMethodNames.java b/src/test/java/com/android/tools/r8/jasmin/InvalidMethodNames.java
index fa2882e..0327b76 100644
--- a/src/test/java/com/android/tools/r8/jasmin/InvalidMethodNames.java
+++ b/src/test/java/com/android/tools/r8/jasmin/InvalidMethodNames.java
@@ -3,8 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.jasmin;
-
-import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.TestParameters;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Arrays;
@@ -27,15 +26,18 @@
@Parameters(name = "\"{0}\", jvm: {1}, art: {2}")
public static Collection<Object[]> data() {
Collection<Object[]> data = new ArrayList<>();
- data.addAll(NameTestBase.getCommonNameTestData(false));
- data.addAll(
- Arrays.asList(
- new Object[][] {
- {new TestString("a/b"), false, false},
- {new TestString("<a"), false, false},
- {new TestString("a>"), !ToolHelper.isJava9Runtime(), false},
- {new TestString("<a>"), false, false}
- }));
+ for (TestParameters parameter : TestParameters.justNoneRuntime()) {
+ parameter.assertNoneRuntime();
+ data.addAll(NameTestBase.getCommonNameTestData());
+ data.addAll(
+ Arrays.asList(
+ new Object[][] {
+ {new TestString("a/b"), false, false},
+ {new TestString("<a"), false, false},
+ {new TestString("a>"), false, false},
+ {new TestString("<a>"), false, false}
+ }));
+ }
return data;
}
diff --git a/src/test/java/com/android/tools/r8/jasmin/NameTestBase.java b/src/test/java/com/android/tools/r8/jasmin/NameTestBase.java
index 594bdbe..0b335a9 100644
--- a/src/test/java/com/android/tools/r8/jasmin/NameTestBase.java
+++ b/src/test/java/com/android/tools/r8/jasmin/NameTestBase.java
@@ -39,51 +39,43 @@
// - Name (String) to test (can be class name, field name, method name).
// - boolean, whether it runs on the JVM.
// - boolean, whether it runs on the ART.
- static Collection<Object[]> getCommonNameTestData(boolean classNames) {
-
- boolean windowsSensitive = classNames && ToolHelper.isWindows();
+ static Collection<Object[]> getCommonNameTestData() {
boolean supportSpaces = ToolHelper.getMinApiLevelForDexVm().getLevel()
>= AndroidApiLevel.R.getLevel();
- boolean java9 = ToolHelper.isJava9Runtime();
-
return Arrays.asList(
new Object[][] {
{new TestString("azAZ09$_"), true, true},
- {new TestString("_"), !java9, true},
- {new TestString("a-b"), !java9, true},
- {new TestString("\u00a0"), !java9, supportSpaces},
- {new TestString("\u00a1"), !java9, true},
- {new TestString("\u1fff"), !java9, true},
- {new TestString("\u2000"), !windowsSensitive && !java9, supportSpaces},
- {new TestString("\u200f"), !windowsSensitive && !java9, false},
- {new TestString("\u2010"), !windowsSensitive && !java9, true},
- {new TestString("\u2027"), !windowsSensitive && !java9, true},
- {new TestString("\u2028"), !windowsSensitive && !java9, false},
- {new TestString("\u202f"), !windowsSensitive && !java9, supportSpaces},
- {new TestString("\u2030"), !windowsSensitive && !java9, true},
- {new TestString("\ud7ff"), !windowsSensitive && !java9, true},
- {new TestString("\ue000"), !windowsSensitive && !java9, true},
- {new TestString("\uffef"), !windowsSensitive && !java9, true},
- {new TestString("\ufff0"), !windowsSensitive && !java9, false},
- {new TestString("\uffff"), !windowsSensitive && !java9, false},
+ {new TestString("_"), false, true},
+ {new TestString("a-b"), false, true},
+ {new TestString("\u00a0"), false, supportSpaces},
+ {new TestString("\u00a1"), false, true},
+ {new TestString("\u1fff"), false, true},
+ {new TestString("\u2000"), false, supportSpaces},
+ {new TestString("\u200f"), false, false},
+ {new TestString("\u2010"), false, true},
+ {new TestString("\u2027"), false, true},
+ {new TestString("\u2028"), false, false},
+ {new TestString("\u202f"), false, supportSpaces},
+ {new TestString("\u2030"), false, true},
+ {new TestString("\ud7ff"), false, true},
+ {new TestString("\ue000"), false, true},
+ {new TestString("\uffef"), false, true},
+ {new TestString("\ufff0"), false, false},
+ {new TestString("\uffff"), false, false},
// Standalone high and low surrogates.
- {new TestString("\ud800"), !classNames && !java9, false},
- {new TestString("\udbff"), !classNames && !java9, false},
- {new TestString("\udc00"), !classNames && !java9, false},
- {new TestString("\udfff"), !classNames && !java9, false},
+ {new TestString("\ud800"), false, false},
+ {new TestString("\udbff"), false, false},
+ {new TestString("\udc00"), false, false},
+ {new TestString("\udfff"), false, false},
// Single and double code points above 0x10000.
{new TestString("\ud800\udc00"), true, true},
{new TestString("\ud800\udcfa"), true, true},
- {new TestString("\ud800\udcfb"), !windowsSensitive && !java9, true},
- {new TestString("\udbff\udfff"), !windowsSensitive && !java9, true},
+ {new TestString("\ud800\udcfb"), false, true},
+ {new TestString("\udbff\udfff"), false, true},
{new TestString("\ud800\udc00\ud800\udcfa"), true, true},
- {
- new TestString("\ud800\udc00\udbff\udfff"),
- !windowsSensitive && !java9,
- true
- }
+ {new TestString("\ud800\udc00\udbff\udfff"), false, true}
});
}
diff --git a/src/test/java/com/android/tools/r8/java_language/pattern_matching_for_instenceof/PattternMatchingForInstanceOfTest.java b/src/test/java/com/android/tools/r8/java_language/pattern_matching_for_instenceof/PattternMatchingForInstanceOfTest.java
index e81d20c..b40cca0 100644
--- a/src/test/java/com/android/tools/r8/java_language/pattern_matching_for_instenceof/PattternMatchingForInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/java_language/pattern_matching_for_instenceof/PattternMatchingForInstanceOfTest.java
@@ -9,7 +9,6 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfVm;
import com.android.tools.r8.examples.jdk17.PatternMatchingForInstanceof;
-import com.android.tools.r8.utils.InternalOptions.TestingOptions;
import com.google.common.collect.ImmutableList;
import java.nio.file.Path;
import java.util.List;
@@ -50,7 +49,6 @@
testForD8(parameters.getBackend())
.addProgramFiles(JAR)
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion)
.compile()
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines(EXPECTED);
@@ -62,8 +60,7 @@
testForR8(parameters.getBackend())
.addProgramFiles(JAR)
.setMinApi(parameters.getApiLevel())
- .addKeepMainRule(MAIN)
- .addOptionsModification(TestingOptions::allowExperimentClassFileVersion);
+ .addKeepMainRule(MAIN);
if (parameters.getBackend().isDex()) {
builder.run(parameters.getRuntime(), MAIN).assertSuccessWithOutputLines(EXPECTED);
} else {
diff --git a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
index c14b357..488271b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
@@ -73,9 +73,8 @@
.count();
long paramNullCheckCount =
countCall(testMethod, "Intrinsics", "checkParameterIsNotNull");
- // TODO(b/214496607): Should be one after Iterator#hasNext, and another in the filter
- // predicate: sinceYear != null.
- assertEquals(testParameters.isCfRuntime() ? 5 : 2, ifzCount);
+ // One after Iterator#hasNext, and another in the filter predicate: sinceYear != null.
+ assertEquals(2, ifzCount);
assertEquals(0, paramNullCheckCount);
});
}
diff --git a/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTest.java b/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTest.java
index 4fb3d8b..11f560d 100644
--- a/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/PublicFieldInnerClassTest.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.StringUtils;
import org.junit.Test;
@@ -75,7 +74,7 @@
@Parameterized.Parameters(name = "Backend: {0}")
public static TestParametersCollection data() {
- return TestParametersBuilder.builder().withAllRuntimesAndApiLevels().build();
+ return TestParameters.builder().withAllRuntimesAndApiLevels().build();
}
public PublicFieldInnerClassTest(TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/resolution/SingleTargetExecutionTest.java b/src/test/java/com/android/tools/r8/resolution/SingleTargetExecutionTest.java
index 1446e76..4726fe4 100644
--- a/src/test/java/com/android/tools/r8/resolution/SingleTargetExecutionTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/SingleTargetExecutionTest.java
@@ -84,6 +84,10 @@
}
private String getExpectedOutput() {
+ String icceOrNot =
+ enableInliningAnnotations || !parameters.canUseDefaultAndStaticInterfaceMethods()
+ ? "ICCE"
+ : "InterfaceWithDefault";
return StringUtils.lines(
"SubSubClassOne",
"SubSubClassOne",
@@ -93,7 +97,7 @@
"com.android.tools.r8.resolution.singletarget.one.AbstractSubClass",
"InterfaceWithDefault",
"InterfaceWithDefault",
- "ICCE",
+ icceOrNot,
"com.android.tools.r8.resolution.singletarget.one.SubSubClassTwo",
"com.android.tools.r8.resolution.singletarget.one.SubSubClassTwo",
"AbstractTopClass",
@@ -105,7 +109,7 @@
"InterfaceWithDefault",
"InterfaceWithDefault",
"InterfaceWithDefault",
- "ICCE",
+ icceOrNot,
"InterfaceWithDefault",
"com.android.tools.r8.resolution.singletarget.one.SubSubClassTwo",
"InterfaceWithDefault",
diff --git a/src/test/java/com/android/tools/r8/resolution/b123730538/B123730538.java b/src/test/java/com/android/tools/r8/resolution/b123730538/B123730538.java
index c61d7fa..029fc63 100644
--- a/src/test/java/com/android/tools/r8/resolution/b123730538/B123730538.java
+++ b/src/test/java/com/android/tools/r8/resolution/b123730538/B123730538.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.resolution.b123730538.runner.PublicClassExtender;
@@ -40,7 +39,7 @@
@Parameterized.Parameters(name = "Backend: {0}")
public static TestParametersCollection data() {
- return TestParametersBuilder.builder().withAllRuntimesAndApiLevels().build();
+ return TestParameters.builder().withAllRuntimesAndApiLevels().build();
}
public B123730538(TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/resource/KeepDirectoriesTest.java b/src/test/java/com/android/tools/r8/resource/KeepDirectoriesTest.java
index 416835f..fedfb29 100644
--- a/src/test/java/com/android/tools/r8/resource/KeepDirectoriesTest.java
+++ b/src/test/java/com/android/tools/r8/resource/KeepDirectoriesTest.java
@@ -16,7 +16,6 @@
import com.android.tools.r8.DiagnosticsHandler;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.naming.ClassNameMapper;
@@ -55,7 +54,7 @@
return buildParameters(
ToolHelper.getBackends(),
BooleanUtils.values(),
- TestParametersBuilder.builder().withNoneRuntime().build());
+ TestParameters.builder().withNoneRuntime().build());
}
public KeepDirectoriesTest(Backend backend, boolean minify, TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestBase.java b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestBase.java
index 4dcd86a..9196e6a 100644
--- a/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestBase.java
+++ b/src/test/java/com/android/tools/r8/retrace/api/RetraceApiTestBase.java
@@ -6,7 +6,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.TestParametersCollection;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -18,7 +17,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return TestParametersBuilder.builder().withNoneRuntime().build();
+ return TestParameters.builder().withNoneRuntime().build();
}
public RetraceApiTestBase(TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java b/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java
index cfffbac..c6c5cc2 100644
--- a/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/switchmaps/RewriteSwitchMapsTest.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.google.common.collect.ImmutableList;
@@ -26,7 +25,7 @@
@Parameterized.Parameters(name = "{0}, backend: {1}")
public static List<Object[]> data() {
return buildParameters(
- TestParametersBuilder.builder().withNoneRuntime().build(), ToolHelper.getBackends());
+ TestParameters.builder().withNoneRuntime().build(), ToolHelper.getBackends());
}
public RewriteSwitchMapsTest(TestParameters parameters, Backend backend) {
diff --git a/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java b/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java
index f42443d..eacb522 100644
--- a/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/TreeShakingSpecificTest.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -43,8 +42,7 @@
@Parameters(name = "Backend: {1}")
public static List<Object[]> data() {
- return buildParameters(
- TestParametersBuilder.builder().withNoneRuntime().build(), Backend.values());
+ return buildParameters(TestParameters.builder().withNoneRuntime().build(), Backend.values());
}
public TreeShakingSpecificTest(TestParameters parameters, Backend backend) {
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByReachableSubclassTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByReachableSubclassTest.java
index b848b1c..ae37674 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByReachableSubclassTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByReachableSubclassTest.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.references.Reference;
@@ -33,7 +32,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return TestParametersBuilder.builder().withCfRuntimes().build();
+ return TestParameters.builder().withCfRuntimes().build();
}
public KeptByReachableSubclassTest(TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java
index b34d36d..f6f59dd 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSingletonIsNotCyclicTest.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.NeverPropagateValue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.references.ClassReference;
@@ -41,7 +40,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return TestParametersBuilder.builder().withCfRuntimes().build();
+ return TestParameters.builder().withCfRuntimes().build();
}
public KeptSingletonIsNotCyclicTest(TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSubclassKeepsSuperTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSubclassKeepsSuperTest.java
index 12d1f35..cd34b55 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSubclassKeepsSuperTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSubclassKeepsSuperTest.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersBuilder;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.references.Reference;
@@ -33,7 +32,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return TestParametersBuilder.builder().withCfRuntimes().build();
+ return TestParameters.builder().withCfRuntimes().build();
}
public KeptSubclassKeepsSuperTest(TestParameters parameters) {
diff --git a/src/test/java/com/android/tools/r8/shaking/proxy/MockitoTest.java b/src/test/java/com/android/tools/r8/shaking/proxy/MockitoTest.java
index 1464e82..d31da79 100644
--- a/src/test/java/com/android/tools/r8/shaking/proxy/MockitoTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/proxy/MockitoTest.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking.proxy;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -57,11 +58,8 @@
.inspector();
ClassSubject itf = inspector.clazz(M_I);
assertThat(itf, isPresent());
- // TODO(b/214496607): This could be removed as a result of devirtualization, but this only
- // happens if the call site is reprocessed, since we don't have knowledge of open/closed
- // interfaces until the second optimization pass.
MethodSubject mtd = itf.uniqueMethodWithName("onEnterForeground");
- assertThat(mtd, isPresent());
+ assertThat(mtd, isAbsent());
}
@Test
diff --git a/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java b/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java
index c850ae8..047a109 100644
--- a/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/proxy/ProxiesTest.java
@@ -139,8 +139,8 @@
private void noInterfaceKept(CodeInspector inspector) {
// Indirectly assert that method is inlined into x, y and z and that redundant field loads
// remove invokes.
- assertEquals(3, countInstructionInX(inspector, InstructionSubject::isInvokeInterface));
- assertEquals(3, countInstructionInY(inspector, InstructionSubject::isInvokeInterface));
+ assertEquals(0, countInstructionInX(inspector, InstructionSubject::isInvokeInterface));
+ assertEquals(0, countInstructionInY(inspector, InstructionSubject::isInvokeInterface));
assertEquals(0, countInstructionInZ(inspector, InstructionSubject::isInvokeVirtual));
}
@@ -149,10 +149,7 @@
runTest(
ImmutableList.of(),
this::noInterfaceKept,
- "TestClass 1\nTestClass 1\nTestClass 1\nProxy\nProxy\nProxy\n"
- + "TestClass 2\nTestClass 2\nTestClass 2\nProxy\nProxy\nProxy\n"
- + "TestClass 3\nTestClass 3\nTestClass 3\n"
- + "TestClass 4\nTestClass 4\nTestClass 4\nSUCCESS\n");
+ "TestClass 1\nTestClass 1\nTestClass 1\nEXCEPTION\n");
}
private void baseInterfaceKept(CodeInspector inspector) {
@@ -160,7 +157,7 @@
assertEquals(3, countInstructionInX(inspector, InstructionSubject::isInvokeInterface));
// Indirectly assert that method is inlined into y and z and that redundant field loads
// remove invokes.
- assertEquals(3, countInstructionInY(inspector, InstructionSubject::isInvokeInterface));
+ assertEquals(0, countInstructionInY(inspector, InstructionSubject::isInvokeInterface));
assertEquals(0, countInstructionInZ(inspector, InstructionSubject::isInvokeVirtual));
assertEquals(0, countInstructionInZSubClass(inspector, InstructionSubject::isInvokeVirtual));
}
@@ -174,9 +171,7 @@
"}"),
this::baseInterfaceKept,
"TestClass 1\nTestClass 1\nTestClass 1\nProxy\nProxy\nProxy\n"
- + "TestClass 2\nTestClass 2\nTestClass 2\nProxy\nProxy\nProxy\n"
- + "TestClass 3\nTestClass 3\nTestClass 3\n"
- + "TestClass 4\nTestClass 4\nTestClass 4\nSUCCESS\n");
+ + "TestClass 2\nTestClass 2\nTestClass 2\nEXCEPTION\n");
}
private void subInterfaceKept(CodeInspector inspector) {
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticMarkerCfTest.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticMarkerCfTest.java
new file mode 100644
index 0000000..706ace9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticMarkerCfTest.java
@@ -0,0 +1,261 @@
+// 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.synthesis;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThrows;
+
+import com.android.tools.r8.ByteDataView;
+import com.android.tools.r8.ClassFileConsumer;
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.transformers.ClassTransformer;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.Box;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.StringUtils;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ByteVector;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+
+@RunWith(Parameterized.class)
+public class SyntheticMarkerCfTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("Hello, world");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ .withDefaultCfRuntime()
+ .withApiLevel(AndroidApiLevel.B)
+ .enableApiLevelsForCf()
+ .build();
+ }
+
+ public SyntheticMarkerCfTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ /**
+ * Mirror of the initial D8 synthetic marker format.
+ *
+ * <p>The legacy marker just had the synthetic kind id as payload.
+ */
+ private static class SyntheticMarkerV1 extends Attribute {
+ static final SyntheticMarkerV1 PROTO = new SyntheticMarkerV1((short) 0);
+
+ final short kindId;
+
+ public SyntheticMarkerV1(short kindId) {
+ super("com.android.tools.r8.SynthesizedClass");
+ this.kindId = kindId;
+ }
+
+ @Override
+ protected Attribute read(
+ ClassReader classReader,
+ int offset,
+ int length,
+ char[] charBuffer,
+ int codeAttributeOffset,
+ Label[] labels) {
+ short id = classReader.readShort(offset);
+ return new SyntheticMarkerV1(id);
+ }
+
+ @Override
+ protected ByteVector write(
+ ClassWriter classWriter, byte[] code, int codeLength, int maxStack, int maxLocals) {
+ ByteVector byteVector = new ByteVector();
+ byteVector.putShort(kindId);
+ return byteVector;
+ }
+ }
+
+ /**
+ * Format of the current synthetic marker.
+ *
+ * <p>The marker is distinguished by a new attribute type name.
+ *
+ * <p>The payload is the kind id, version hash length and then version hash bytes.
+ */
+ private static class SyntheticMarkerV2 extends Attribute {
+ static final SyntheticMarkerV2 PROTO = new SyntheticMarkerV2((short) 0, null);
+
+ final short kindId;
+ final byte[] versionHash;
+
+ public SyntheticMarkerV2(short kindId, byte[] versionHash) {
+ super("com.android.tools.r8.SynthesizedClassV2");
+ this.versionHash = versionHash;
+ this.kindId = kindId;
+ }
+
+ @Override
+ protected Attribute read(
+ ClassReader classReader,
+ int offset,
+ int length,
+ char[] charBuffer,
+ int codeAttributeOffset,
+ Label[] labels) {
+ short kindId = classReader.readShort(offset);
+ offset += 2;
+ short versionLength = classReader.readShort(offset);
+ offset += 2;
+ byte[] versionBytes = new byte[versionLength];
+ for (int i = 0; i < versionLength; i++) {
+ versionBytes[i] = (byte) classReader.readByte(offset++);
+ }
+ return new SyntheticMarkerV2(kindId, versionBytes);
+ }
+
+ @Override
+ protected ByteVector write(
+ ClassWriter classWriter, byte[] code, int codeLength, int maxStack, int maxLocals) {
+ ByteVector byteVector = new ByteVector();
+ byteVector.putShort(kindId);
+ byteVector.putShort(versionHash.length);
+ byteVector.putByteArray(versionHash, 0, versionHash.length);
+ return byteVector;
+ }
+ }
+
+ private static List<Attribute> readAttributes(byte[] bytes) {
+ List<Attribute> attributes = new ArrayList<>();
+ ClassReader reader = new ClassReader(bytes);
+ reader.accept(
+ new ClassVisitor(InternalOptions.ASM_VERSION) {
+ @Override
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ @Override
+ public void visitAttribute(Attribute attribute) {
+ attributes.add(attribute);
+ }
+ },
+ new Attribute[] {SyntheticMarkerV1.PROTO, SyntheticMarkerV2.PROTO},
+ ClassReader.SKIP_CODE | ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
+ return attributes;
+ }
+
+ private byte[] getTestClassWithMarker(Attribute marker) throws IOException {
+ return transformer(TestClass.class)
+ .addClassTransformer(
+ new ClassTransformer() {
+ @Override
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ super.visit(version, access, name, signature, superName, interfaces);
+ super.visitAttribute(marker);
+ }
+ })
+ .transform();
+ }
+
+ /** Test that reads the correct marker from a compilation unit and fails if then manipulated. */
+ @Test
+ public void testInvalidMarkerFailsCompilation() throws Exception {
+ Box<SyntheticMarkerV2> currentCompilerMarker = new Box<>();
+ testForD8(parameters.getBackend())
+ .addProgramClasses(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .setIntermediate(true)
+ .setProgramConsumer(
+ new ClassFileConsumer() {
+ private final List<Attribute> attributes = new ArrayList<>();
+
+ @Override
+ public void accept(ByteDataView data, String descriptor, DiagnosticsHandler handler) {
+ attributes.addAll(readAttributes(data.copyByteData()));
+ }
+
+ @Override
+ public void finished(DiagnosticsHandler handler) {
+ assertEquals(1, attributes.size());
+ assertEquals(SyntheticMarkerV2.PROTO.type, attributes.get(0).type);
+ currentCompilerMarker.set((SyntheticMarkerV2) attributes.get(0));
+ }
+ })
+ .compile()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+
+ // Test that if a "current" marker with invalid content is given to the compiler it will
+ // cause a failure. This test ensures that we can witness the markers being ignored in the
+ // tests below.
+ D8TestBuilder builder =
+ testForD8(parameters.getBackend())
+ .setMinApi(parameters.getApiLevel())
+ .addProgramClassFileData(
+ getTestClassWithMarker(
+ new SyntheticMarkerV2(
+ Short.MAX_VALUE, currentCompilerMarker.get().versionHash)));
+ assertThrows(CompilationFailedException.class, builder::compile);
+ }
+
+ @Test
+ public void testIgnoreV1Markers() throws Exception {
+ // Test that inputs with a legacy marker will be ignored.
+ // We do so by injecting an old marker and put in a non-valid ID which would cause the compiler
+ // to fail if it was read.
+ testForD8(parameters.getBackend())
+ .setMinApi(parameters.getApiLevel())
+ .addProgramClassFileData(getTestClassWithMarker(new SyntheticMarkerV1(Short.MAX_VALUE)))
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void testIgnorePreviousV2Markers() throws Exception {
+ // Test that inputs with a V2 marker from a previous compiler version are ignored.
+ // We do so by injecting an old marker and put in a non-valid ID which would cause the compiler
+ // to fail if it was read.
+ testForD8(parameters.getBackend())
+ .setMinApi(parameters.getApiLevel())
+ .addProgramClassFileData(
+ getTestClassWithMarker(new SyntheticMarkerV2(Short.MAX_VALUE, new byte[0])))
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ public static class TestClass {
+
+ public static void run(Runnable r) {
+ r.run();
+ }
+
+ public static void main(String[] args) {
+ run(() -> System.out.println("Hello, world"));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticMarkerDexTest.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticMarkerDexTest.java
new file mode 100644
index 0000000..5b00775
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticMarkerDexTest.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.synthesis;
+
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.graph.DexAnnotation;
+import com.android.tools.r8.graph.DexEncodedAnnotation;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.nio.file.Path;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class SyntheticMarkerDexTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("Hello, world");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDefaultDexRuntime().withApiLevel(AndroidApiLevel.B).build();
+ }
+
+ public SyntheticMarkerDexTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ Path out =
+ testForD8(parameters.getBackend())
+ .setMinApi(parameters.getApiLevel())
+ .setIntermediate(true)
+ .addProgramClasses(TestClass.class)
+ .compile()
+ .inspect(this::checkSyntheticClassIsMarked)
+ .writeToZip();
+ testForD8(parameters.getBackend())
+ .setMinApi(parameters.getApiLevel())
+ .addProgramFiles(out)
+ // Use intermediate again to preserve synthetics.
+ .setIntermediate(true)
+ // Disable desugaring so we are sure the lambda synthetic is created in the first round.
+ .disableDesugaring()
+ .compile()
+ .inspect(this::checkSyntheticClassIsMarked)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ private void checkSyntheticClassIsMarked(CodeInspector inspector) {
+ // Compilation gives rise to the main class plus one lambda.
+ assertEquals(2, inspector.allClasses().size());
+ inspector.forAllClasses(
+ clazz -> {
+ if (!clazz.getFinalReference().equals(Reference.classFromClass(TestClass.class))) {
+ // This should be the lambda class.
+ DexAnnotation[] annotations = clazz.getDexProgramClass().annotations().annotations;
+ assertEquals(1, annotations.length);
+ DexEncodedAnnotation annotation = annotations[0].annotation;
+ assertEquals(2, annotation.elements.length);
+ assertEquals(
+ "com.android.tools.r8.annotations.SynthesizedClassV2",
+ annotation.type.toSourceString());
+ }
+ });
+ }
+
+ public static class TestClass {
+
+ public static void run(Runnable r) {
+ r.run();
+ }
+
+ public static void main(String[] args) {
+ run(() -> System.out.println("Hello, world"));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/utils/TestParametersTest.java b/src/test/java/com/android/tools/r8/utils/TestParametersTest.java
index 7d26b86..a217b8c 100644
--- a/src/test/java/com/android/tools/r8/utils/TestParametersTest.java
+++ b/src/test/java/com/android/tools/r8/utils/TestParametersTest.java
@@ -31,7 +31,7 @@
assumeFalse(
"Test is only valid when no runtimes property is set",
TestParametersBuilder.isRuntimesPropertySet());
- TestParametersCollection params = TestParametersBuilder.builder().withNoneRuntime().build();
+ TestParametersCollection params = TestParameters.builder().withNoneRuntime().build();
assertTrue(params.stream().anyMatch(TestParameters::isNoneRuntime));
}
@@ -40,7 +40,7 @@
assumeFalse(
"Test is only valid when no runtimes property is set",
TestParametersBuilder.isRuntimesPropertySet());
- TestParametersCollection params = TestParametersBuilder.builder().withAllRuntimes().build();
+ TestParametersCollection params = TestParameters.builder().withAllRuntimes().build();
assertTrue(params.stream().noneMatch(TestParameters::isNoneRuntime));
assertTrue(params.stream().anyMatch(TestParameters::isDexRuntime));
assertTrue(params.stream().anyMatch(TestParameters::isCfRuntime));
@@ -53,7 +53,7 @@
TestParametersBuilder.isRuntimesPropertySet());
// This test may also fail once the tests can be configured for with API levels to run.
TestParametersCollection params =
- TestParametersBuilder.builder().withAllRuntimesAndApiLevels().build();
+ TestParameters.builder().withAllRuntimesAndApiLevels().build();
assertTrue(params.stream().noneMatch(TestParameters::isNoneRuntime));
assertTrue(params.stream().anyMatch(p -> p.isCfRuntime() && p.getApiLevel() == null));
// Default API levels are min and max for each DEX VM.
@@ -79,12 +79,9 @@
public void testJdk9Presence() {
assumeTrue(!TestParametersBuilder.isRuntimesPropertySet()
|| TestParametersBuilder.getRuntimesProperty().contains("jdk9"));
- assertTrue(TestParametersBuilder
- .builder()
- .withAllRuntimesAndApiLevels()
- .build()
- .stream()
- .anyMatch(parameter -> parameter.getRuntime().equals(TestRuntime.getCheckedInJdk9())));
+ assertTrue(
+ TestParameters.builder().withAllRuntimesAndApiLevels().build().stream()
+ .anyMatch(parameter -> parameter.getRuntime().equals(TestRuntime.getCheckedInJdk9())));
}
@Test
@@ -92,12 +89,9 @@
assumeTrue(ToolHelper.isLinux());
assumeTrue(!TestParametersBuilder.isRuntimesPropertySet()
|| TestParametersBuilder.getRuntimesProperty().contains("dex-default"));
- assertTrue(TestParametersBuilder
- .builder()
- .withAllRuntimesAndApiLevels()
- .build()
- .stream()
- .anyMatch(parameter -> parameter.getRuntime().name().equals("dex-default")));
+ assertTrue(
+ TestParameters.builder().withAllRuntimesAndApiLevels().build().stream()
+ .anyMatch(parameter -> parameter.getRuntime().name().equals("dex-default")));
}
@Test
@@ -105,11 +99,8 @@
assumeTrue(ToolHelper.isLinux());
assumeTrue(!TestParametersBuilder.isRuntimesPropertySet()
|| TestParametersBuilder.getRuntimesProperty().contains("dex-4.4.4"));
- assertTrue(TestParametersBuilder
- .builder()
- .withAllRuntimesAndApiLevels()
- .build()
- .stream()
- .anyMatch(parameter -> parameter.getRuntime().name().equals("dex-4.4.4")));
+ assertTrue(
+ TestParameters.builder().withAllRuntimesAndApiLevels().build().stream()
+ .anyMatch(parameter -> parameter.getRuntime().name().equals("dex-4.4.4")));
}
}
diff --git a/third_party/r8-releases/3.2.54.tar.gz.sha1 b/third_party/r8-releases/3.2.54.tar.gz.sha1
new file mode 100644
index 0000000..dac3b33
--- /dev/null
+++ b/third_party/r8-releases/3.2.54.tar.gz.sha1
@@ -0,0 +1 @@
+f1019609a854b348981e65b34b401c15d93eb91f
\ No newline at end of file
diff --git a/tools/internal_test.py b/tools/internal_test.py
index df4174f..8e4caa5 100755
--- a/tools/internal_test.py
+++ b/tools/internal_test.py
@@ -111,6 +111,8 @@
# TODO(b/210982978): Enable testing of min xmx again
TEST_COMMANDS = [
+ # Make sure we have a clean build to not be polluted by old test files
+ ['tools/gradle.py', 'clean'],
# Run test.py internal testing.
['tools/test.py', '--only_internal', '--slow_tests',
'--java_max_memory_size=8G'],
diff --git a/tools/jdk.py b/tools/jdk.py
index 23cacc8..ea6be86 100755
--- a/tools/jdk.py
+++ b/tools/jdk.py
@@ -3,14 +3,18 @@
# 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.
-import defines
import os
import sys
+import defines
+
JDK_DIR = os.path.join(defines.THIRD_PARTY, 'openjdk')
def GetJdkHome():
- root = os.path.join(JDK_DIR, 'openjdk-9.0.4')
+ return GetJdk9Home()
+
+def GetJdk11Home():
+ root = os.path.join(JDK_DIR, 'jdk-11')
if defines.IsLinux():
return os.path.join(root, 'linux')
elif defines.IsOsX():
@@ -20,8 +24,8 @@
else:
return os.environ['JAVA_HOME']
-def GetJdk11Home():
- root = os.path.join(JDK_DIR, 'jdk-11')
+def GetJdk9Home():
+ root = os.path.join(JDK_DIR, 'openjdk-9.0.4')
if defines.IsLinux():
return os.path.join(root, 'linux')
elif defines.IsOsX():
diff --git a/tools/trigger.py b/tools/trigger.py
index 2b9816a..d467a81 100755
--- a/tools/trigger.py
+++ b/tools/trigger.py
@@ -13,7 +13,7 @@
import subprocess
import sys
import urllib
-
+from urllib.request import urlopen
import utils
LUCI_SCHEDULE = os.path.join(utils.REPO_ROOT, 'infra', 'config', 'global',
@@ -47,7 +47,7 @@
with open(LUCI_SCHEDULE, 'r') as fp:
lines = fp.readlines()
for line in lines:
- if 'branch-gitiles-trigger' in line:
+ if 'branch-gitiles' in line:
is_release = True
if 'main-gitiles-trigger' in line:
is_release = False
@@ -66,7 +66,7 @@
return (main_builders, release_builders)
def sanity_check_url(url):
- a = urllib.urlopen(url)
+ a = urlopen(url)
if a.getcode() != 200:
raise Exception('Url: %s \n returned %s' % (url, a.getcode()))
@@ -85,15 +85,15 @@
def Main():
(options, args) = ParseOptions()
if len(args) != 1 and not options.cl and not options.desugar:
- print 'Takes exactly one argument, the commit to run'
+ print('Takes exactly one argument, the commit to run')
return 1
if options.cl and options.release:
- print 'You can\'t run cls on the release bots'
+ print('You can\'t run cls on the release bots')
return 1
if options.cl and options.desugar:
- print 'You can\'t run cls on the desugar bot'
+ print('You can\'t run cls on the desugar bot')
return 1
commit = None if (options.cl or options.desugar) else args[0]