Merge commit '7c8734d1ec8841da7b99d0c09025d2ac5497a62e' into dev-release
diff --git a/.gitignore b/.gitignore
index bbe6eea..a5b9426 100644
--- a/.gitignore
+++ b/.gitignore
@@ -99,19 +99,27 @@
third_party/kotlin/kotlin-compiler-1.3.41
third_party/kotlin/kotlin-compiler-1.3.72.tar.gz
third_party/kotlin/kotlin-compiler-1.3.72
+third_party/kotlin/kotlin-compiler-1.4.20.tar.gz
+third_party/kotlin/kotlin-compiler-1.4.20
third_party/kotlinx-coroutines-1.3.6.tar.gz
third_party/kotlinx-coroutines-1.3.6
third_party/nest/*
third_party/openjdk/desugar_jdk_libs
third_party/openjdk/desugar_jdk_libs.tar.gz
+third_party/openjdk/jdk-15/linux
+third_party/openjdk/jdk-15/linux.tar.gz
+third_party/openjdk/jdk-15/osx
+third_party/openjdk/jdk-15/osx.tar.gz
+third_party/openjdk/jdk-15/windows
+third_party/openjdk/jdk-15/windows.tar.gz
third_party/openjdk/jdk-11-test
third_party/openjdk/jdk-11-test.tar.gz
-third_party/openjdk/jdk-11/Linux
-third_party/openjdk/jdk-11/Linux.tar.gz
-third_party/openjdk/jdk-11/Mac
-third_party/openjdk/jdk-11/Mac.tar.gz
-third_party/openjdk/jdk-11/Windows
-third_party/openjdk/jdk-11/Windows.tar.gz
+third_party/openjdk/jdk-11/linux
+third_party/openjdk/jdk-11/linux.tar.gz
+third_party/openjdk/jdk-11/osx
+third_party/openjdk/jdk-11/osx.tar.gz
+third_party/openjdk/jdk-11/windows
+third_party/openjdk/jdk-11/windows.tar.gz
third_party/openjdk/jdk8/darwin-x86
third_party/openjdk/jdk8/darwin-x86.tar.gz
third_party/openjdk/jdk8/linux-x86
diff --git a/build.gradle b/build.gradle
index 981dcfd..be64cba 100644
--- a/build.gradle
+++ b/build.gradle
@@ -22,7 +22,7 @@
jcenter()
}
dependencies {
- classpath 'com.github.jengelman.gradle.plugins:shadow:4.0.2'
+ classpath 'com.github.jengelman.gradle.plugins:shadow:5.2.0'
}
}
@@ -35,7 +35,7 @@
ext {
androidSupportVersion = '25.4.0'
- asmVersion = '8.0' // When updating update tools/asmifier.py and Toolhelper as well.
+ asmVersion = '9.0' // When updating update tools/asmifier.py and Toolhelper as well.
espressoVersion = '3.0.0'
fastutilVersion = '7.2.0'
guavaVersion = '23.0'
@@ -135,6 +135,11 @@
srcDirs = ['src/test/examplesJava11']
}
}
+ examplesJava15 {
+ java {
+ srcDirs = ['src/test/examplesJava15']
+ }
+ }
jdk11TimeTests {
java {
srcDirs = [
@@ -287,7 +292,7 @@
def r8DesugaredPath = "$buildDir/libs/r8desugared.jar"
def r8LibGeneratedKeepRulesPath = "$buildDir/generated/keep.txt"
def r8LibTestPath = "$buildDir/classes/r8libtest"
-def java11ClassFiles = "build/classes/java/mainJava11"
+def java11ClassFiles = "$buildDir/classes/java/mainJava11"
def osString = OperatingSystem.current().isLinux() ? "linux" :
OperatingSystem.current().isMacOsX() ? "mac" : "windows"
@@ -362,16 +367,19 @@
linux: [
"third_party": ["openjdk/openjdk-9.0.4/linux",
"openjdk/jdk8/linux-x86",
- "openjdk/jdk-11/Linux"],
+ "openjdk/jdk-11/linux",
+ "openjdk/jdk-15/linux"],
],
osx: [
"third_party": ["openjdk/openjdk-9.0.4/osx",
"openjdk/jdk8/darwin-x86",
- "openjdk/jdk-11/Mac"],
+ "openjdk/jdk-11/osx",
+ "openjdk/jdk-15/osx"],
],
windows: [
"third_party": ["openjdk/openjdk-9.0.4/windows",
- "openjdk/jdk-11/Windows"],
+ "openjdk/jdk-11/windows",
+ "openjdk/jdk-15/windows"],
],
]
@@ -555,42 +563,61 @@
}
}
-tasks.named(sourceSets.examplesJava9.compileJavaTaskName).get().configure {
- def jdkDir = 'third_party/openjdk/openjdk-9.0.4/'
- options.fork = true
- options.forkOptions.jvmArgs = []
- if (OperatingSystem.current().isLinux()) {
- options.forkOptions.javaHome = file(jdkDir + 'linux')
- } else if (OperatingSystem.current().isMacOsX()) {
- options.forkOptions.javaHome = file(jdkDir + 'osx')
- } else {
- options.forkOptions.javaHome = file(jdkDir + 'windows')
- }
- sourceCompatibility = JavaVersion.VERSION_1_9
- targetCompatibility = JavaVersion.VERSION_1_9
-}
-
-def setJdk11CompilationWithCompatibility(String sourceSet, JavaVersion compatibility) {
+def setJdkCompilationWithCompatibility(String sourceSet, String javaHome, JavaVersion compatibility, boolean enablePreview) {
tasks.named(sourceSet).get().configure {
- def jdkDir = 'third_party/openjdk/jdk-11/'
+ def jdkDir = "third_party/openjdk/${javaHome}/"
options.fork = true
options.forkOptions.jvmArgs = []
+ if (enablePreview) {
+ options.compilerArgs.add('--enable-preview')
+ }
if (OperatingSystem.current().isLinux()) {
- options.forkOptions.javaHome = file(jdkDir + 'Linux')
+ options.forkOptions.javaHome = file(jdkDir + 'linux')
} else if (OperatingSystem.current().isMacOsX()) {
- options.forkOptions.javaHome = file(jdkDir + 'Mac/Contents/Home')
+ options.forkOptions.javaHome = file(jdkDir + 'osx')
} else {
- options.forkOptions.javaHome = file(jdkDir + 'Windows')
+ options.forkOptions.javaHome = file(jdkDir + 'windows')
}
sourceCompatibility = compatibility
targetCompatibility = compatibility
}
}
-setJdk11CompilationWithCompatibility(sourceSets.examplesJava10.compileJavaTaskName, JavaVersion.VERSION_1_10)
-setJdk11CompilationWithCompatibility(sourceSets.examplesJava11.compileJavaTaskName, JavaVersion.VERSION_11)
-setJdk11CompilationWithCompatibility(sourceSets.examplesTestNGRunner.compileJavaTaskName, JavaVersion.VERSION_11)
-setJdk11CompilationWithCompatibility(sourceSets.jdk11TimeTests.compileJavaTaskName, JavaVersion.VERSION_11)
+setJdkCompilationWithCompatibility(
+ sourceSets.examplesJava9.compileJavaTaskName,
+ 'openjdk-9.0.4',
+ JavaVersion.VERSION_1_9,
+ false)
+setJdkCompilationWithCompatibility(
+ sourceSets.examplesJava11.compileJavaTaskName,
+ 'jdk-11',
+ JavaVersion.VERSION_11,
+ false)
+setJdkCompilationWithCompatibility(
+ sourceSets.examplesJava10.compileJavaTaskName,
+ 'jdk-11',
+ JavaVersion.VERSION_1_10,
+ false)
+setJdkCompilationWithCompatibility(
+ sourceSets.examplesJava11.compileJavaTaskName,
+ 'jdk-11',
+ JavaVersion.VERSION_11,
+ false)
+setJdkCompilationWithCompatibility(
+ sourceSets.examplesTestNGRunner.compileJavaTaskName,
+ 'jdk-11',
+ JavaVersion.VERSION_11,
+ false)
+setJdkCompilationWithCompatibility(
+ sourceSets.jdk11TimeTests.compileJavaTaskName,
+ 'jdk-11',
+ JavaVersion.VERSION_11,
+ false)
+setJdkCompilationWithCompatibility(
+ sourceSets.examplesJava15.compileJavaTaskName,
+ 'jdk-15',
+ JavaVersion.VERSION_15,
+ true)
task compileMainWithJava11 (type: JavaCompile) {
dependsOn downloadDeps
@@ -598,11 +625,11 @@
options.fork = true
options.forkOptions.jvmArgs = []
if (OperatingSystem.current().isLinux()) {
- options.forkOptions.javaHome = file(jdkDir + 'Linux')
+ options.forkOptions.javaHome = file(jdkDir + 'linux')
} else if (OperatingSystem.current().isMacOsX()) {
- options.forkOptions.javaHome = file(jdkDir + 'Mac/Contents/Home')
+ options.forkOptions.javaHome = file(jdkDir + 'osx/Contents/Home')
} else {
- options.forkOptions.javaHome = file(jdkDir + 'Windows')
+ options.forkOptions.javaHome = file(jdkDir + 'windows')
}
source = sourceSets.main.allSource
destinationDir = file(java11ClassFiles)
@@ -714,6 +741,8 @@
}
task repackageSourcesNew(type: ShadowJar) {
+ // If this fails then remove all generated folders from
+ // build/classes/java/test that is not {com,dalvik}
from sourceSets.main.output
mergeServiceFiles(it)
baseName 'sources_main'
@@ -730,6 +759,7 @@
return tasks.create("r8Create${name}", ShadowJar) {
from consolidatedLicense.outputs.files
from sources
+ exclude "$buildDir/classes/**"
baseName baseNameName
classifier = null
version = null
@@ -1519,53 +1549,28 @@
}
}
-task buildExampleJava9Jars {
- def examplesDir = file("src/test/examplesJava9")
- examplesDir.eachDir { dir ->
- def name = dir.getName();
- def exampleOutputDir = file("build/test/examplesJava9");
- def jarName = "${name}.jar"
- dependsOn "jar_examplesJava9_${name}"
- task "jar_examplesJava9_${name}"(type: Jar) {
- archiveName = jarName
- destinationDir = exampleOutputDir
- from sourceSets.examplesJava9.output
- include "**/" + name + "/**/*.class"
+def buildExampleJarsCreateTask(javaVersion, sourceSet) {
+ return tasks.create("buildExample${javaVersion}Jars") {
+ def examplesDir = file("src/test/examples${javaVersion}")
+ examplesDir.eachDir { dir ->
+ def name = dir.getName();
+ def exampleOutputDir = file("build/test/examples${javaVersion}");
+ def jarName = "${name}.jar"
+ dependsOn "jar_examples${javaVersion}_${name}"
+ task "jar_examples${javaVersion}_${name}"(type: Jar) {
+ archiveName = jarName
+ destinationDir = exampleOutputDir
+ from sourceSet.output
+ include "**/" + name + "/**/*.class"
+ }
}
}
}
-task buildExampleJava10Jars {
- def examplesDir = file("src/test/examplesJava10")
- examplesDir.eachDir { dir ->
- def name = dir.getName();
- def exampleOutputDir = file("build/test/examplesJava10");
- def jarName = "${name}.jar"
- dependsOn "jar_examplesJava10_${name}"
- task "jar_examplesJava10_${name}"(type: Jar) {
- archiveName = jarName
- destinationDir = exampleOutputDir
- from sourceSets.examplesJava10.output
- include "**/" + name + "/**/*.class"
- }
- }
-}
-
-task buildExampleJava11Jars {
- def examplesDir = file("src/test/examplesJava11")
- examplesDir.eachDir { dir ->
- def name = dir.getName();
- def exampleOutputDir = file("build/test/examplesJava11");
- def jarName = "${name}.jar"
- dependsOn "jar_examplesJava11_${name}"
- task "jar_examplesJava11_${name}"(type: Jar) {
- archiveName = jarName
- destinationDir = exampleOutputDir
- from sourceSets.examplesJava11.output
- include "**/" + name + "/**/*.class"
- }
- }
-}
+buildExampleJarsCreateTask("Java9", sourceSets.examplesJava9)
+buildExampleJarsCreateTask("Java10", sourceSets.examplesJava10)
+buildExampleJarsCreateTask("Java11", sourceSets.examplesJava11)
+buildExampleJarsCreateTask("Java15", sourceSets.examplesJava15)
task provideArtFrameworksDependencies {
cloudDependencies.tools.forEach({ art ->
@@ -1685,6 +1690,7 @@
dependsOn buildExampleJava9Jars
dependsOn buildExampleJava10Jars
dependsOn buildExampleJava11Jars
+ dependsOn buildExampleJava15Jars
dependsOn buildExampleAndroidApi
def examplesDir = file("src/test/examples")
def noDexTests = [
diff --git a/gradle.properties b/gradle.properties
new file mode 100644
index 0000000..41fabcc
--- /dev/null
+++ b/gradle.properties
@@ -0,0 +1,5 @@
+# Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+# for details. All rights reserved. Use of this source code is governed by a
+# BSD-style license that can be found in the LICENSE file.
+
+org.gradle.jvmargs=-Xmx2048M
\ No newline at end of file
diff --git a/src/main/java/com/android/tools/r8/D8Command.java b/src/main/java/com/android/tools/r8/D8Command.java
index e9dbc44..f720ee9 100644
--- a/src/main/java/com/android/tools/r8/D8Command.java
+++ b/src/main/java/com/android/tools/r8/D8Command.java
@@ -414,7 +414,7 @@
// Assert some of R8 optimizations are disabled.
assert !internal.enableInlining;
assert !internal.enableClassInlining;
- assert !internal.enableHorizontalClassMerging;
+ assert internal.horizontalClassMergerOptions().isDisabled();
assert !internal.enableStaticClassMerging;
assert !internal.enableVerticalClassMerging;
assert !internal.enableClassStaticizer;
diff --git a/src/main/java/com/android/tools/r8/DiagnosticsHandler.java b/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
index de3f800..295d52d 100644
--- a/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
+++ b/src/main/java/com/android/tools/r8/DiagnosticsHandler.java
@@ -39,7 +39,8 @@
*/
default void warning(Diagnostic warning) {
if (warning.getOrigin() != Origin.unknown()) {
- System.err.print("Warning in " + warning.getOrigin() + ":\n ");
+ System.err.println("Warning in " + warning.getOrigin() + ":");
+ System.err.print(" ");
} else {
System.err.print("Warning: ");
}
@@ -53,7 +54,10 @@
*/
default void info(Diagnostic info) {
if (info.getOrigin() != Origin.unknown()) {
- System.out.print("In " + info.getOrigin() + ":\n ");
+ System.out.println("Info in " + info.getOrigin() + ":");
+ System.out.print(" ");
+ } else {
+ System.out.print("Info: ");
}
System.out.println(info.getDiagnosticMessage());
}
diff --git a/src/main/java/com/android/tools/r8/L8Command.java b/src/main/java/com/android/tools/r8/L8Command.java
index dce2b21..fff3341 100644
--- a/src/main/java/com/android/tools/r8/L8Command.java
+++ b/src/main/java/com/android/tools/r8/L8Command.java
@@ -168,7 +168,7 @@
// Assert some of R8 optimizations are disabled.
assert !internal.enableInlining;
assert !internal.enableClassInlining;
- assert !internal.enableHorizontalClassMerging;
+ assert internal.horizontalClassMergerOptions().isDisabled();
assert !internal.enableStaticClassMerging;
assert !internal.enableVerticalClassMerging;
assert !internal.enableClassStaticizer;
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index cfb3540..089c747 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -33,10 +33,10 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.DirectMappedDexApplication.Builder;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.graph.InitClassLens;
+import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.graph.analysis.ClassInitializerAssertionEnablingAnalysis;
import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis;
@@ -61,7 +61,6 @@
import com.android.tools.r8.ir.optimize.UnusedArgumentsCollector;
import com.android.tools.r8.ir.optimize.UnusedArgumentsCollector.UnusedArgumentsGraphLens;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxingCfMethods;
-import com.android.tools.r8.ir.optimize.enums.EnumValueInfoMapCollector;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.ir.optimize.templates.CfUtilityMethodsForCodeOptimizations;
import com.android.tools.r8.jar.CfApplicationWriter;
@@ -419,8 +418,12 @@
// Recompute the subtyping information.
Set<DexType> removedClasses = pruner.getRemovedClasses();
- appView.removePrunedClasses(
- prunedApp, removedClasses, pruner.getMethodsToKeepForConfigurationDebugging());
+ appView.pruneItems(
+ PrunedItems.builder()
+ .setPrunedApp(prunedApp)
+ .addRemovedClasses(removedClasses)
+ .addAdditionalPinnedItems(pruner.getMethodsToKeepForConfigurationDebugging())
+ .build());
new AbstractMethodRemover(
appViewWithLiveness, appViewWithLiveness.appInfo().computeSubtypingInfo())
.run();
@@ -578,7 +581,9 @@
timing.end();
}
}
- if (options.enableHorizontalClassMerging && options.enableInlining) {
+ if (options.horizontalClassMergerOptions().isEnabled()
+ && options.enableInlining
+ && options.isShrinking()) {
timing.begin("HorizontalClassMerger");
HorizontalClassMerger merger = new HorizontalClassMerger(appViewWithLiveness);
DirectMappedDexApplication.Builder appBuilder =
@@ -587,7 +592,12 @@
merger.run(appBuilder, mainDexTracingResult, runtimeTypeCheckInfo);
if (lens != null) {
DirectMappedDexApplication app = appBuilder.build();
- appView.removePrunedClasses(app, appView.horizontallyMergedClasses().getSources());
+ appView.pruneItems(
+ PrunedItems.builder()
+ .setPrunedApp(app)
+ .addRemovedClasses(appView.horizontallyMergedClasses().getSources())
+ .addNoLongerSyntheticItems(appView.horizontallyMergedClasses().getTargets())
+ .build());
appView.rewriteWithLens(lens);
// Only required for class merging, clear instance to save memory.
@@ -606,18 +616,11 @@
if (options.enableEnumSwitchMapRemoval) {
appViewWithLiveness.setAppInfo(new SwitchMapCollector(appViewWithLiveness).run());
}
- if (options.enableEnumValueOptimization || options.enableEnumUnboxing) {
- appViewWithLiveness.setAppInfo(new EnumValueInfoMapCollector(appViewWithLiveness).run());
- }
// Collect the already pruned types before creating a new app info without liveness.
// TODO: we should avoid removing liveness.
Set<DexType> prunedTypes = appView.withLiveness().appInfo().getPrunedTypes();
- // TODO: move to appview.
- EnumValueInfoMapCollection enumValueInfoMapCollection =
- appViewWithLiveness.appInfo().getEnumValueInfoMapCollection();
-
timing.begin("Create IR");
CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
try {
@@ -717,13 +720,11 @@
missingClasses,
prunedTypes);
appView.setAppInfo(
- enqueuer
- .traceApplication(
- appView.rootSet(),
- options.getProguardConfiguration().getDontWarnPatterns(),
- executorService,
- timing)
- .withEnumValueInfoMaps(enumValueInfoMapCollection));
+ enqueuer.traceApplication(
+ appView.rootSet(),
+ options.getProguardConfiguration().getDontWarnPatterns(),
+ executorService,
+ timing));
// Rerunning the enqueuer should not give rise to any method rewritings.
assert enqueuer.buildGraphLens() == null;
appView.withGeneratedMessageLiteBuilderShrinker(
@@ -748,10 +749,12 @@
options.reporter, options.usageInformationConsumer);
}
- appView.removePrunedClasses(
- application,
- CollectionUtils.mergeSets(prunedTypes, removedClasses),
- pruner.getMethodsToKeepForConfigurationDebugging());
+ appView.pruneItems(
+ PrunedItems.builder()
+ .setPrunedApp(application)
+ .addRemovedClasses(CollectionUtils.mergeSets(prunedTypes, removedClasses))
+ .addAdditionalPinnedItems(pruner.getMethodsToKeepForConfigurationDebugging())
+ .build());
new BridgeHoisting(appViewWithLiveness).run();
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 40be618..29112ed 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -869,7 +869,8 @@
? LineNumberOptimization.ON
: LineNumberOptimization.OFF;
- assert proguardConfiguration.isOptimizing() || !internal.enableHorizontalClassMerging;
+ assert proguardConfiguration.isOptimizing()
+ || internal.horizontalClassMergerOptions().isDisabled();
assert internal.enableStaticClassMerging || !proguardConfiguration.isOptimizing();
assert !internal.enableTreeShakingOfLibraryMethodOverrides;
assert internal.enableVerticalClassMerging || !proguardConfiguration.isOptimizing();
@@ -879,7 +880,7 @@
internal.getProguardConfiguration().getKeepAttributes().localVariableTypeTable = true;
internal.enableInlining = false;
internal.enableClassInlining = false;
- internal.enableHorizontalClassMerging = false;
+ internal.horizontalClassMergerOptions().disable();
internal.enableStaticClassMerging = false;
internal.enableVerticalClassMerging = false;
internal.enableClassStaticizer = false;
@@ -891,7 +892,7 @@
// If R8 is not shrinking, there is no point in running various optimizations since the
// optimized classes will still remain in the program (the application size could increase).
internal.enableEnumUnboxing = false;
- internal.enableHorizontalClassMerging = false;
+ internal.horizontalClassMergerOptions().disable();
internal.enableLambdaMerging = false;
internal.enableStaticClassMerging = false;
internal.enableVerticalClassMerging = false;
@@ -900,7 +901,7 @@
if (!internal.enableInlining) {
// If R8 cannot perform inlining, then the synthetic constructors would not inline the called
// constructors, producing invalid code.
- internal.enableHorizontalClassMerging = false;
+ internal.horizontalClassMergerOptions().disable();
}
// Amend the proguard-map consumer with options from the proguard configuration.
@@ -958,7 +959,7 @@
if (internal.isGeneratingClassFiles()) {
internal.outline.enabled = false;
internal.enableEnumUnboxing = false;
- internal.enableHorizontalClassMerging = false;
+ internal.horizontalClassMergerOptions().disable();
}
// EXPERIMENTAL flags.
diff --git a/src/main/java/com/android/tools/r8/cf/CfVersion.java b/src/main/java/com/android/tools/r8/cf/CfVersion.java
index 100656f..a69cc03 100644
--- a/src/main/java/com/android/tools/r8/cf/CfVersion.java
+++ b/src/main/java/com/android/tools/r8/cf/CfVersion.java
@@ -23,6 +23,10 @@
public static final CfVersion V9 = new CfVersion(Opcodes.V9);
public static final CfVersion V10 = new CfVersion(Opcodes.V10);
public static final CfVersion V11 = new CfVersion(Opcodes.V11);
+ public static final CfVersion V12 = new CfVersion(Opcodes.V12);
+ public static final CfVersion V13 = new CfVersion(Opcodes.V13);
+ public static final CfVersion V14 = new CfVersion(Opcodes.V14);
+ public static final CfVersion V15 = new CfVersion(Opcodes.V15);
private final int version;
@@ -68,7 +72,7 @@
@Override
public int hashCode() {
- return HashCodeVisitor.run(this, CfVersion::specify);
+ return HashCodeVisitor.run(this);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/CheckCast.java b/src/main/java/com/android/tools/r8/code/CheckCast.java
index 32df17b..9f3739a 100644
--- a/src/main/java/com/android/tools/r8/code/CheckCast.java
+++ b/src/main/java/com/android/tools/r8/code/CheckCast.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
public class CheckCast extends Format21c<DexType> {
@@ -44,8 +45,8 @@
}
@Override
- int internalCompareBBBB(Format21c<?> other) {
- return BBBB.compareTo((DexType) other.BBBB);
+ void internalSubSpecify(StructuralSpecification<Format21c<DexType>, ?> spec) {
+ spec.withItem(i -> i.BBBB);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstClass.java b/src/main/java/com/android/tools/r8/code/ConstClass.java
index ce1c26b..b96f4aa 100644
--- a/src/main/java/com/android/tools/r8/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/code/ConstClass.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
public class ConstClass extends Format21c<DexType> {
@@ -29,8 +30,8 @@
}
@Override
- int internalCompareBBBB(Format21c<?> other) {
- return BBBB.compareTo((DexType) other.BBBB);
+ void internalSubSpecify(StructuralSpecification<Format21c<DexType>, ?> spec) {
+ spec.withItem(i -> i.BBBB);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java b/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
index 0409f06..2f05b0b 100644
--- a/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
public class ConstMethodHandle extends Format21c<DexMethodHandle> {
@@ -51,8 +52,8 @@
}
@Override
- int internalCompareBBBB(Format21c<?> other) {
- return BBBB.compareTo((DexMethodHandle) other.BBBB);
+ void internalSubSpecify(StructuralSpecification<Format21c<DexMethodHandle>, ?> spec) {
+ spec.withItem(i -> i.BBBB);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstMethodType.java b/src/main/java/com/android/tools/r8/code/ConstMethodType.java
index 8f54c24..7662fe4 100644
--- a/src/main/java/com/android/tools/r8/code/ConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/code/ConstMethodType.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
public class ConstMethodType extends Format21c<DexProto> {
@@ -50,8 +51,8 @@
}
@Override
- int internalCompareBBBB(Format21c<?> other) {
- return BBBB.compareTo((DexProto) other.BBBB);
+ void internalSubSpecify(StructuralSpecification<Format21c<DexProto>, ?> spec) {
+ spec.withItem(i -> i.BBBB);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstString.java b/src/main/java/com/android/tools/r8/code/ConstString.java
index e9e910d..5fd55e4 100644
--- a/src/main/java/com/android/tools/r8/code/ConstString.java
+++ b/src/main/java/com/android/tools/r8/code/ConstString.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
public class ConstString extends Format21c<DexString> {
@@ -34,8 +35,8 @@
}
@Override
- int internalCompareBBBB(Format21c<?> other) {
- return BBBB.compareTo((DexString) other.BBBB);
+ void internalSubSpecify(StructuralSpecification<Format21c<DexString>, ?> spec) {
+ spec.withItem(i -> i.BBBB);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/DexInitClass.java b/src/main/java/com/android/tools/r8/code/DexInitClass.java
index ab39c88..8e85bd0 100644
--- a/src/main/java/com/android/tools/r8/code/DexInitClass.java
+++ b/src/main/java/com/android/tools/r8/code/DexInitClass.java
@@ -16,8 +16,9 @@
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
-import java.util.Comparator;
public class DexInitClass extends Base2Format {
@@ -28,6 +29,10 @@
private final int dest;
private final DexType clazz;
+ private static void specify(StructuralSpecification<DexInitClass, ?> spec) {
+ spec.withInt(i -> i.dest).withItem(i -> i.clazz);
+ }
+
public DexInitClass(int dest, DexType clazz) {
assert clazz.isClassType();
this.dest = dest;
@@ -127,10 +132,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- return Comparator.comparingInt((DexInitClass i) -> i.dest)
- .thenComparing(i -> i.clazz)
- .compare(this, (DexInitClass) other);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (DexInitClass) other, DexInitClass::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java b/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java
index 18bdfd3..1a434fd 100644
--- a/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
public class DexItemBasedConstString extends Format21c<DexReference> {
@@ -68,8 +69,8 @@
}
@Override
- int internalCompareBBBB(Format21c<?> other) {
- return BBBB.referenceCompareTo(((DexItemBasedConstString) other).BBBB);
+ void internalSubSpecify(StructuralSpecification<Format21c<DexReference>, ?> spec) {
+ spec.withDexReference(i -> i.BBBB);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java b/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java
index 52d3e07..cab0270 100644
--- a/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java
+++ b/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java
@@ -9,11 +9,11 @@
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
import java.util.Arrays;
-import java.util.Comparator;
public class FillArrayDataPayload extends Nop {
@@ -21,6 +21,10 @@
public final long size;
public final short[] data;
+ private static void specify(StructuralSpecification<FillArrayDataPayload, ?> spec) {
+ spec.withInt(i -> i.element_width).withLong(i -> i.size).withShortArray(i -> i.data);
+ }
+
FillArrayDataPayload(int high, BytecodeStream stream) {
super(high, stream);
element_width = read16BitValue(stream);
@@ -62,11 +66,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- return Comparator.comparingInt((FillArrayDataPayload i) -> i.element_width)
- .thenComparingLong(i -> i.size)
- .thenComparing(i -> i.data, ComparatorUtils::compareShortArray)
- .compare(this, (FillArrayDataPayload) other);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (FillArrayDataPayload) other, FillArrayDataPayload::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/FilledNewArray.java b/src/main/java/com/android/tools/r8/code/FilledNewArray.java
index a1ee0ba..5198876 100644
--- a/src/main/java/com/android/tools/r8/code/FilledNewArray.java
+++ b/src/main/java/com/android/tools/r8/code/FilledNewArray.java
@@ -43,11 +43,6 @@
}
@Override
- int internalCompareBBBB(Format35c<?> other) {
- return BBBB.compareTo((DexType) other.BBBB);
- }
-
- @Override
public void collectIndexedItems(
IndexedItemCollection indexedItems,
ProgramMethod context,
diff --git a/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java b/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
index 03594c2..de651f5 100644
--- a/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
+++ b/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
@@ -43,11 +43,6 @@
}
@Override
- int internalCompareBBBB(Format3rc<?> other) {
- return BBBB.compareTo((DexType) other.BBBB);
- }
-
- @Override
public void collectIndexedItems(
IndexedItemCollection indexedItems,
ProgramMethod context,
diff --git a/src/main/java/com/android/tools/r8/code/Format10t.java b/src/main/java/com/android/tools/r8/code/Format10t.java
index 528ef92..9b2b11c 100644
--- a/src/main/java/com/android/tools/r8/code/Format10t.java
+++ b/src/main/java/com/android/tools/r8/code/Format10t.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.nio.ShortBuffer;
abstract class Format10t extends Base1Format {
@@ -43,8 +44,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- return Byte.compare(AA, ((Format10t) other).AA);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visitInt(AA, ((Format10t) other).AA);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format11n.java b/src/main/java/com/android/tools/r8/code/Format11n.java
index 61d845e..27c0d27 100644
--- a/src/main/java/com/android/tools/r8/code/Format11n.java
+++ b/src/main/java/com/android/tools/r8/code/Format11n.java
@@ -10,13 +10,18 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
abstract class Format11n extends Base1Format {
public final byte A, B;
+ private static void specify(StructuralSpecification<Format11n, ?> spec) {
+ spec.withInt(i -> i.A).withInt(i -> i.B);
+ }
+
// #+B | vA | op
/*package*/ Format11n(int high, BytecodeStream stream) {
super(stream);
@@ -53,9 +58,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format11n o = (Format11n) other;
- return ComparatorUtils.compareInts(A, o.A, B, o.B);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format11n) other, Format11n::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format11x.java b/src/main/java/com/android/tools/r8/code/Format11x.java
index 4509fbd..3cc3b73 100644
--- a/src/main/java/com/android/tools/r8/code/Format11x.java
+++ b/src/main/java/com/android/tools/r8/code/Format11x.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.nio.ShortBuffer;
abstract class Format11x extends Base1Format {
@@ -43,8 +44,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- return Short.compare(AA, ((Format11x) other).AA);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visitInt(AA, ((Format11x) other).AA);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format12x.java b/src/main/java/com/android/tools/r8/code/Format12x.java
index db7ca5a..f3b80aa 100644
--- a/src/main/java/com/android/tools/r8/code/Format12x.java
+++ b/src/main/java/com/android/tools/r8/code/Format12x.java
@@ -10,13 +10,18 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
abstract class Format12x extends Base1Format {
public final byte A, B;
+ private static void specify(StructuralSpecification<Format12x, ?> spec) {
+ spec.withInt(i -> i.A).withInt(i -> i.B);
+ }
+
// vB | vA | op
Format12x(int high, BytecodeStream stream) {
super(stream);
@@ -47,9 +52,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format12x o = (Format12x) other;
- return ComparatorUtils.compareInts(A, o.A, B, o.B);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format12x) other, Format12x::specify);
}
diff --git a/src/main/java/com/android/tools/r8/code/Format20t.java b/src/main/java/com/android/tools/r8/code/Format20t.java
index 8f34250..c9cd18b 100644
--- a/src/main/java/com/android/tools/r8/code/Format20t.java
+++ b/src/main/java/com/android/tools/r8/code/Format20t.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.nio.ShortBuffer;
abstract class Format20t extends Base2Format {
@@ -43,8 +44,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- return Short.compare(AAAA, ((Format20t) other).AAAA);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visitInt(AAAA, ((Format20t) other).AAAA);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format21c.java b/src/main/java/com/android/tools/r8/code/Format21c.java
index 074b79a..9416be7 100644
--- a/src/main/java/com/android/tools/r8/code/Format21c.java
+++ b/src/main/java/com/android/tools/r8/code/Format21c.java
@@ -6,6 +6,8 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.function.BiPredicate;
abstract class Format21c<T extends IndexedDexItem> extends Base2Format {
@@ -31,14 +33,16 @@
return ((BBBB.hashCode() << 8) | AA) ^ getClass().hashCode();
}
+ @SuppressWarnings("unchecked")
@Override
- final int internalCompareTo(Instruction other) {
- Format21c<?> o = (Format21c<?>) other;
- int aaDiff = Short.compare(AA, o.AA);
- return aaDiff != 0 ? aaDiff : internalCompareBBBB(o);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(
+ this,
+ (Format21c<T>) other,
+ spec -> spec.withInt(i -> i.AA).withSpec(this::internalSubSpecify));
}
- abstract int internalCompareBBBB(Format21c<?> other);
+ abstract void internalSubSpecify(StructuralSpecification<Format21c<T>, ?> spec);
@Override
public String toString(ClassNameMapper naming) {
diff --git a/src/main/java/com/android/tools/r8/code/Format21h.java b/src/main/java/com/android/tools/r8/code/Format21h.java
index 537a020..36b9174 100644
--- a/src/main/java/com/android/tools/r8/code/Format21h.java
+++ b/src/main/java/com/android/tools/r8/code/Format21h.java
@@ -9,7 +9,8 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
abstract class Format21h extends Base2Format {
@@ -17,6 +18,10 @@
public final short AA;
public final char BBBB;
+ private static void specify(StructuralSpecification<Format21h, ?> spec) {
+ spec.withInt(i -> i.AA).withInt(i -> i.BBBB);
+ }
+
// AA | op | BBBB0000[00000000]
/*package*/ Format21h(int high, BytecodeStream stream) {
super(stream);
@@ -48,9 +53,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format21h o = (Format21h) other;
- return ComparatorUtils.compareInts(AA, o.AA, BBBB, o.BBBB);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format21h) other, Format21h::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format21s.java b/src/main/java/com/android/tools/r8/code/Format21s.java
index 3f4e0fc..550fdd4 100644
--- a/src/main/java/com/android/tools/r8/code/Format21s.java
+++ b/src/main/java/com/android/tools/r8/code/Format21s.java
@@ -10,8 +10,9 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
abstract class Format21s extends Base2Format {
@@ -19,6 +20,10 @@
public final short AA;
public final short BBBB;
+ private static void specify(StructuralSpecification<Format21s, ?> spec) {
+ spec.withInt(i -> i.AA).withInt(i -> i.BBBB);
+ }
+
// AA | op | #+BBBB
/*package*/ Format21s(int high, BytecodeStream stream) {
super(stream);
@@ -50,9 +55,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format21s o = (Format21s) other;
- return ComparatorUtils.compareInts(AA, o.AA, BBBB, o.BBBB);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format21s) other, Format21s::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format21t.java b/src/main/java/com/android/tools/r8/code/Format21t.java
index e580a1f..bde930d 100644
--- a/src/main/java/com/android/tools/r8/code/Format21t.java
+++ b/src/main/java/com/android/tools/r8/code/Format21t.java
@@ -13,7 +13,8 @@
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
public abstract class Format21t extends Base2Format {
@@ -21,6 +22,10 @@
public final short AA;
public /* offset */ short BBBB;
+ private static void specify(StructuralSpecification<Format21t, ?> spec) {
+ spec.withInt(i -> i.AA).withInt(i -> i.BBBB);
+ }
+
// AA | op | +BBBB
Format21t(int high, BytecodeStream stream) {
super(stream);
@@ -52,9 +57,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format21t o = (Format21t) other;
- return ComparatorUtils.compareInts(AA, o.AA, BBBB, o.BBBB);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format21t) other, Format21t::specify);
}
public abstract Type getType();
diff --git a/src/main/java/com/android/tools/r8/code/Format22b.java b/src/main/java/com/android/tools/r8/code/Format22b.java
index 5bbd0da..6f79b50 100644
--- a/src/main/java/com/android/tools/r8/code/Format22b.java
+++ b/src/main/java/com/android/tools/r8/code/Format22b.java
@@ -10,8 +10,9 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
public abstract class Format22b extends Base2Format {
@@ -20,6 +21,10 @@
public final short BB;
public final byte CC;
+ private static void specify(StructuralSpecification<Format22b, ?> spec) {
+ spec.withInt(i -> i.AA).withInt(i -> i.BB).withInt(i -> i.CC);
+ }
+
// vAA | op | #+CC | VBB
/*package*/ Format22b(int high, BytecodeStream stream) {
super(stream);
@@ -54,9 +59,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format22b o = (Format22b) other;
- return ComparatorUtils.compareInts(AA, o.AA, BB, o.BB, CC, o.CC);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format22b) other, Format22b::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format22c.java b/src/main/java/com/android/tools/r8/code/Format22c.java
index bd16c8f..536ec65 100644
--- a/src/main/java/com/android/tools/r8/code/Format22c.java
+++ b/src/main/java/com/android/tools/r8/code/Format22c.java
@@ -7,7 +7,8 @@
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.function.BiPredicate;
public abstract class Format22c<T extends DexReference> extends Base2Format {
@@ -16,6 +17,10 @@
public final byte B;
public T CCCC;
+ private static void specify(StructuralSpecification<Format22c<? extends DexReference>, ?> spec) {
+ spec.withInt(i -> i.A).withInt(i -> i.B).withDexReference(i -> i.CCCC);
+ }
+
// vB | vA | op | [type|field]@CCCC
/*package*/ Format22c(int high, BytecodeStream stream, T[] map) {
super(stream);
@@ -38,10 +43,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format22c<? extends DexReference> o = (Format22c<? extends DexReference>) other;
- int diff = ComparatorUtils.compareInts(A, o.A, B, o.B);
- return diff != 0 ? diff : CCCC.referenceCompareTo(o.CCCC);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format22c<? extends DexReference>) other, Format22c::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format22s.java b/src/main/java/com/android/tools/r8/code/Format22s.java
index 8492eae..efa14d2 100644
--- a/src/main/java/com/android/tools/r8/code/Format22s.java
+++ b/src/main/java/com/android/tools/r8/code/Format22s.java
@@ -10,8 +10,9 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
public abstract class Format22s extends Base2Format {
@@ -20,6 +21,10 @@
public final byte B;
public final short CCCC;
+ private static void specify(StructuralSpecification<Format22s, ?> spec) {
+ spec.withInt(i -> i.A).withInt(i -> i.B).withInt(i -> i.CCCC);
+ }
+
// vB | vA | op | #+CCCC
/*package*/ Format22s(int high, BytecodeStream stream) {
super(stream);
@@ -54,9 +59,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format22s o = (Format22s) other;
- return ComparatorUtils.compareInts(A, o.A, B, o.B, CCCC, o.CCCC);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format22s) other, Format22s::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format22t.java b/src/main/java/com/android/tools/r8/code/Format22t.java
index 5c64988..9688b4e 100644
--- a/src/main/java/com/android/tools/r8/code/Format22t.java
+++ b/src/main/java/com/android/tools/r8/code/Format22t.java
@@ -13,7 +13,8 @@
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
public abstract class Format22t extends Base2Format {
@@ -22,6 +23,10 @@
public final byte B;
public /* offset */ short CCCC;
+ private static void specify(StructuralSpecification<Format22t, ?> spec) {
+ spec.withInt(i -> i.A).withInt(i -> i.B).withInt(i -> i.CCCC);
+ }
+
// vB | vA | op | +CCCC
Format22t(int high, BytecodeStream stream) {
super(stream);
@@ -56,9 +61,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format22t o = (Format22t) other;
- return ComparatorUtils.compareInts(A, o.A, B, o.B, CCCC, o.CCCC);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format22t) other, Format22t::specify);
}
public abstract Type getType();
diff --git a/src/main/java/com/android/tools/r8/code/Format22x.java b/src/main/java/com/android/tools/r8/code/Format22x.java
index 626e7f9..1d9d8ba 100644
--- a/src/main/java/com/android/tools/r8/code/Format22x.java
+++ b/src/main/java/com/android/tools/r8/code/Format22x.java
@@ -10,7 +10,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
abstract class Format22x extends Base2Format {
@@ -18,6 +19,10 @@
public final short AA;
public final char BBBB;
+ private static void specify(StructuralSpecification<Format22x, ?> spec) {
+ spec.withInt(i -> i.AA).withInt(i -> i.BBBB);
+ }
+
// AA | op | vBBBB
Format22x(int high, BytecodeStream stream) {
super(stream);
@@ -49,9 +54,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format22x o = (Format22x) other;
- return ComparatorUtils.compareInts(AA, o.AA, BBBB, o.BBBB);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format22x) other, Format22x::specify);
}
diff --git a/src/main/java/com/android/tools/r8/code/Format23x.java b/src/main/java/com/android/tools/r8/code/Format23x.java
index a87dddf..ca3ef80 100644
--- a/src/main/java/com/android/tools/r8/code/Format23x.java
+++ b/src/main/java/com/android/tools/r8/code/Format23x.java
@@ -10,7 +10,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
abstract class Format23x extends Base2Format {
@@ -19,6 +20,10 @@
public final short BB;
public final short CC;
+ private static void specify(StructuralSpecification<Format23x, ?> spec) {
+ spec.withInt(i -> i.AA).withInt(i -> i.BB).withInt(i -> i.CC);
+ }
+
// vAA | op | vCC | vBB
Format23x(int high, BytecodeStream stream) {
super(stream);
@@ -53,9 +58,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format23x o = (Format23x) other;
- return ComparatorUtils.compareInts(AA, o.AA, BB, o.BB, CC, o.CC);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format23x) other, Format23x::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format30t.java b/src/main/java/com/android/tools/r8/code/Format30t.java
index 81dcf86..ba986cc 100644
--- a/src/main/java/com/android/tools/r8/code/Format30t.java
+++ b/src/main/java/com/android/tools/r8/code/Format30t.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
import java.nio.ShortBuffer;
abstract class Format30t extends Base3Format {
@@ -42,8 +43,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- return Integer.compare(AAAAAAAA, ((Format30t) other).AAAAAAAA);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visitInt(AAAAAAAA, ((Format30t) other).AAAAAAAA);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format31c.java b/src/main/java/com/android/tools/r8/code/Format31c.java
index 672057b..6664662 100644
--- a/src/main/java/com/android/tools/r8/code/Format31c.java
+++ b/src/main/java/com/android/tools/r8/code/Format31c.java
@@ -13,6 +13,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
import java.util.function.BiPredicate;
@@ -21,6 +23,10 @@
public final short AA;
public DexString BBBBBBBB;
+ private static void specify(StructuralSpecification<Format31c, ?> spec) {
+ spec.withInt(i -> i.AA).withItem(i -> i.BBBBBBBB);
+ }
+
// vAA | op | string@BBBBlo | string@#+BBBBhi
Format31c(int high, BytecodeStream stream, DexString[] map) {
super(stream);
@@ -51,10 +57,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format31c o = (Format31c) other;
- int diff = Short.compare(AA, o.AA);
- return diff != 0 ? diff : BBBBBBBB.compareTo(o.BBBBBBBB);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format31c) other, Format31c::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format31i.java b/src/main/java/com/android/tools/r8/code/Format31i.java
index 3d0d27e..c2fa1b1 100644
--- a/src/main/java/com/android/tools/r8/code/Format31i.java
+++ b/src/main/java/com/android/tools/r8/code/Format31i.java
@@ -10,7 +10,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
abstract class Format31i extends Base3Format {
@@ -18,6 +19,10 @@
public final short AA;
public final int BBBBBBBB;
+ private static void specify(StructuralSpecification<Format31i, ?> spec) {
+ spec.withInt(i -> i.AA).withInt(i -> i.BBBBBBBB);
+ }
+
// vAA | op | #+BBBBlo | #+BBBBhi
/*package*/ Format31i(int high, BytecodeStream stream) {
super(stream);
@@ -48,9 +53,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format31i o = (Format31i) other;
- return ComparatorUtils.compareInts(AA, o.AA, BBBBBBBB, o.BBBBBBBB);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format31i) other, Format31i::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format31t.java b/src/main/java/com/android/tools/r8/code/Format31t.java
index 8e36d79..f85aca6 100644
--- a/src/main/java/com/android/tools/r8/code/Format31t.java
+++ b/src/main/java/com/android/tools/r8/code/Format31t.java
@@ -10,7 +10,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
public abstract class Format31t extends Base3Format {
@@ -18,6 +19,10 @@
public final short AA;
protected /* offset */ int BBBBBBBB;
+ private static void specify(StructuralSpecification<Format31t, ?> spec) {
+ spec.withInt(i -> i.AA).withInt(i -> i.BBBBBBBB);
+ }
+
// vAA | op | +BBBBlo | +BBBBhi
Format31t(int high, BytecodeStream stream) {
super(stream);
@@ -63,9 +68,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format31t o = (Format31t) other;
- return ComparatorUtils.compareInts(AA, o.AA, BBBBBBBB, o.BBBBBBBB);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format31t) other, Format31t::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format32x.java b/src/main/java/com/android/tools/r8/code/Format32x.java
index a5360db..c637383 100644
--- a/src/main/java/com/android/tools/r8/code/Format32x.java
+++ b/src/main/java/com/android/tools/r8/code/Format32x.java
@@ -11,7 +11,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
abstract class Format32x extends Base3Format {
@@ -19,6 +20,10 @@
public final int AAAA;
public final int BBBB;
+ private static void specify(StructuralSpecification<Format32x, ?> spec) {
+ spec.withInt(i -> i.AAAA).withInt(i -> i.BBBB);
+ }
+
// øø | op | AAAA | BBBB
Format32x(int high, BytecodeStream stream) {
super(stream);
@@ -51,9 +56,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format32x o = (Format32x) other;
- return ComparatorUtils.compareInts(AAAA, o.AAAA, BBBB, o.BBBB);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format32x) other, Format32x::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format35c.java b/src/main/java/com/android/tools/r8/code/Format35c.java
index 8e446db..e5d2489 100644
--- a/src/main/java/com/android/tools/r8/code/Format35c.java
+++ b/src/main/java/com/android/tools/r8/code/Format35c.java
@@ -6,10 +6,12 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.function.BiPredicate;
-public abstract class Format35c<T extends IndexedDexItem> extends Base3Format {
+public abstract class Format35c<T extends IndexedDexItem & StructuralItem<T>> extends Base3Format {
public final byte A;
public final byte C;
@@ -19,6 +21,17 @@
public final byte G;
public T BBBB;
+ private static <T extends IndexedDexItem & StructuralItem<T>> void specify(
+ StructuralSpecification<Format35c<T>, ?> spec) {
+ spec.withInt(i -> i.A)
+ .withInt(i -> i.C)
+ .withInt(i -> i.D)
+ .withInt(i -> i.E)
+ .withInt(i -> i.F)
+ .withInt(i -> i.G)
+ .withItem(i -> i.BBBB);
+ }
+
// A | G | op | BBBB | F | E | D | C
Format35c(int high, BytecodeStream stream, T[] map) {
super(stream);
@@ -55,22 +68,12 @@
| G) ^ getClass().hashCode();
}
+ @SuppressWarnings("unchecked")
@Override
- final int internalCompareTo(Instruction other) {
- Format35c<?> o = (Format35c<?>) other;
- int diff =
- ComparatorUtils.compareInts(
- A, o.A,
- C, o.C,
- D, o.D,
- E, o.E,
- F, o.F,
- G, o.G);
- return diff != 0 ? diff : internalCompareBBBB(o);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format35c<T>) other, Format35c::specify);
}
- abstract int internalCompareBBBB(Format35c<?> other);
-
private void appendRegisterArguments(StringBuilder builder, String separator) {
builder.append("{ ");
int[] values = new int[]{C, D, E, F, G};
diff --git a/src/main/java/com/android/tools/r8/code/Format3rc.java b/src/main/java/com/android/tools/r8/code/Format3rc.java
index 9102ecb..0ceeb4a 100644
--- a/src/main/java/com/android/tools/r8/code/Format3rc.java
+++ b/src/main/java/com/android/tools/r8/code/Format3rc.java
@@ -6,15 +6,22 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.function.BiPredicate;
-public abstract class Format3rc<T extends IndexedDexItem> extends Base3Format {
+public abstract class Format3rc<T extends IndexedDexItem & StructuralItem<T>> extends Base3Format {
public final short AA;
public final char CCCC;
public T BBBB;
+ private static <T extends IndexedDexItem & StructuralItem<T>> void specify(
+ StructuralSpecification<Format3rc<T>, ?> spec) {
+ spec.withInt(i -> i.AA).withInt(i -> i.CCCC).withItem(i -> i.BBBB);
+ }
+
// AA | op | [meth|type]@BBBBB | CCCC
Format3rc(int high, BytecodeStream stream, T[] map) {
super(stream);
@@ -40,15 +47,12 @@
return ((CCCC << 24) | (BBBB.hashCode() << 4) | AA) ^ getClass().hashCode();
}
+ @SuppressWarnings("unchecked")
@Override
- final int internalCompareTo(Instruction other) {
- Format3rc<?> o = (Format3rc<?>) other;
- int diff = ComparatorUtils.compareInts(AA, o.AA, CCCC, o.CCCC);
- return diff != 0 ? diff : internalCompareBBBB(o);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format3rc<T>) other, Format3rc::specify);
}
- abstract int internalCompareBBBB(Format3rc<?> other);
-
private void appendRegisterRange(StringBuilder builder) {
int firstRegister = CCCC;
builder.append("{ ");
diff --git a/src/main/java/com/android/tools/r8/code/Format45cc.java b/src/main/java/com/android/tools/r8/code/Format45cc.java
index bb0e1c7..1542015 100644
--- a/src/main/java/com/android/tools/r8/code/Format45cc.java
+++ b/src/main/java/com/android/tools/r8/code/Format45cc.java
@@ -16,7 +16,8 @@
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
/** Format45cc for instructions of size 4, with 5 registers and 2 constant pool index. */
@@ -31,6 +32,17 @@
public DexMethod BBBB;
public DexProto HHHH;
+ private static void specify(StructuralSpecification<Format45cc, ?> spec) {
+ spec.withInt(i -> i.A)
+ .withInt(i -> i.C)
+ .withInt(i -> i.D)
+ .withInt(i -> i.E)
+ .withInt(i -> i.F)
+ .withInt(i -> i.G)
+ .withItem(i -> i.BBBB)
+ .withItem(i -> i.HHHH);
+ }
+
Format45cc(int high, BytecodeStream stream, DexMethod[] methodMap, DexProto[] protoMap) {
super(stream);
G = (byte) (high & 0xf);
@@ -77,21 +89,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- Format45cc o = (Format45cc) other;
- int diff =
- ComparatorUtils.compareInts(
- A, o.A,
- C, o.C,
- D, o.D,
- E, o.E,
- F, o.F,
- G, o.G);
- if (diff != 0) {
- return diff;
- }
- int bDiff = BBBB.compareTo(o.BBBB);
- return bDiff != 0 ? bDiff : HHHH.compareTo(o.HHHH);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format45cc) other, Format45cc::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format4rcc.java b/src/main/java/com/android/tools/r8/code/Format4rcc.java
index f29357d..4da5b40 100644
--- a/src/main/java/com/android/tools/r8/code/Format4rcc.java
+++ b/src/main/java/com/android/tools/r8/code/Format4rcc.java
@@ -15,8 +15,9 @@
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
-import java.util.Comparator;
import java.util.function.BiPredicate;
/** Format4rcc for instructions of size 4, with a range of registers and 2 constant pool index. */
@@ -27,6 +28,10 @@
public DexMethod BBBB;
public DexProto HHHH;
+ private static void specify(StructuralSpecification<Format4rcc, ?> spec) {
+ spec.withInt(i -> i.AA).withInt(i -> i.CCCC).withItem(i -> i.BBBB).withItem(i -> i.HHHH);
+ }
+
// AA | op | [meth]@BBBB | CCCC | [proto]@HHHH
Format4rcc(int high, BytecodeStream stream, DexMethod[] methodMap, DexProto[] protoMap) {
super(stream);
@@ -70,12 +75,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- return Comparator.comparingInt((Format4rcc i) -> i.AA)
- .thenComparingInt(i -> i.CCCC)
- .thenComparing(i -> i.BBBB)
- .thenComparing(i -> i.HHHH)
- .compare(this, (Format4rcc) other);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format4rcc) other, Format4rcc::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format51l.java b/src/main/java/com/android/tools/r8/code/Format51l.java
index 6c583c4..1417bf8 100644
--- a/src/main/java/com/android/tools/r8/code/Format51l.java
+++ b/src/main/java/com/android/tools/r8/code/Format51l.java
@@ -10,14 +10,19 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
-import java.util.Comparator;
abstract class Format51l extends Base5Format {
public final short AA;
public final long BBBBBBBBBBBBBBBB;
+ private static void specify(StructuralSpecification<Format51l, ?> spec) {
+ spec.withInt(i -> i.AA).withLong(i -> i.BBBBBBBBBBBBBBBB);
+ }
+
// AA | op | BBBB | BBBB | BBBB | BBBB
Format51l(int high, BytecodeStream stream) {
super(stream);
@@ -48,10 +53,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- return Comparator.comparingInt((Format51l i) -> i.AA)
- .thenComparingLong(i -> i.BBBBBBBBBBBBBBBB)
- .compare(this, (Format51l) other);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (Format51l) other, Format51l::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Instruction.java b/src/main/java/com/android/tools/r8/code/Instruction.java
index 52aa90d..977dafd 100644
--- a/src/main/java/com/android/tools/r8/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.InternalCompilerError;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
@@ -19,10 +20,15 @@
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.Equatable;
+import com.android.tools.r8.utils.structural.HashingVisitor;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralMapping;
import java.nio.ShortBuffer;
import java.util.function.BiPredicate;
-public abstract class Instruction implements CfOrDexInstruction, Comparable<Instruction> {
+public abstract class Instruction implements CfOrDexInstruction, StructuralItem<Instruction> {
public static final Instruction[] EMPTY_ARRAY = {};
public final static int[] NO_TARGETS = null;
@@ -294,26 +300,39 @@
@Override
public final boolean equals(Object other) {
- return other instanceof Instruction && compareTo((Instruction) other) == 0;
+ return Equatable.equalsImpl(this, other);
}
@Override
public abstract int hashCode();
+ @Override
+ public Instruction self() {
+ return this;
+ }
+
+ @Override
+ public StructuralMapping<Instruction> getStructuralMapping() {
+ throw new Unreachable();
+ }
+
int getCompareToId() {
return getOpcode();
}
// Abstract compare-to called only if the opcode/compare-id of the instruction matches.
- abstract int internalCompareTo(Instruction other);
+ abstract int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor);
@Override
- public final int compareTo(Instruction other) {
- if (this == other) {
- return 0;
- }
- int opcodeDiff = Integer.compare(getCompareToId(), other.getCompareToId());
- return opcodeDiff != 0 ? opcodeDiff : internalCompareTo(other);
+ public final int acceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ int opcodeDiff = visitor.visitInt(getCompareToId(), other.getCompareToId());
+ return opcodeDiff != 0 ? opcodeDiff : internalAcceptCompareTo(other, visitor);
+ }
+
+ @Override
+ public final void acceptHashing(HashingVisitor visitor) {
+ // Rather than traverse the full instruction, the compare ID will likely give a reasonable hash.
+ visitor.visitInt(getCompareToId());
}
public abstract String getName();
diff --git a/src/main/java/com/android/tools/r8/code/InvokeCustom.java b/src/main/java/com/android/tools/r8/code/InvokeCustom.java
index fb6660a..1355f13 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeCustom.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeCustom.java
@@ -44,11 +44,6 @@
}
@Override
- int internalCompareBBBB(Format35c<?> other) {
- return BBBB.compareTo((DexCallSite) other.BBBB);
- }
-
- @Override
public void collectIndexedItems(
IndexedItemCollection indexedItems,
ProgramMethod context,
diff --git a/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java b/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java
index 71e8399..2d09e4f 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java
@@ -44,11 +44,6 @@
}
@Override
- int internalCompareBBBB(Format3rc<?> other) {
- return BBBB.compareTo((DexCallSite) other.BBBB);
- }
-
- @Override
public void collectIndexedItems(
IndexedItemCollection indexedItems,
ProgramMethod context,
diff --git a/src/main/java/com/android/tools/r8/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/code/InvokeMethod.java
index ec8e6c4..9e5d8f2 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeMethod.java
@@ -42,11 +42,6 @@
public abstract Invoke.Type getInvokeType();
@Override
- int internalCompareBBBB(Format35c<?> other) {
- return BBBB.compareTo((DexMethod) other.BBBB);
- }
-
- @Override
public void write(
ShortBuffer dest,
ProgramMethod context,
diff --git a/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java b/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java
index 19c2bf1..ba248e0 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java
@@ -42,11 +42,6 @@
public abstract Type getInvokeType();
@Override
- int internalCompareBBBB(Format3rc<?> other) {
- return BBBB.compareTo((DexMethod) other.BBBB);
- }
-
- @Override
public void write(
ShortBuffer dest,
ProgramMethod context,
diff --git a/src/main/java/com/android/tools/r8/code/NewInstance.java b/src/main/java/com/android/tools/r8/code/NewInstance.java
index 0b90d1a..44d2613 100644
--- a/src/main/java/com/android/tools/r8/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/code/NewInstance.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
public class NewInstance extends Format21c<DexType> {
@@ -44,8 +45,8 @@
}
@Override
- int internalCompareBBBB(Format21c<?> other) {
- return BBBB.compareTo((DexType) other.BBBB);
+ void internalSubSpecify(StructuralSpecification<Format21c<DexType>, ?> spec) {
+ spec.withItem(i -> i.BBBB);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Nop.java b/src/main/java/com/android/tools/r8/code/Nop.java
index ae56ec8..1e46cfc 100644
--- a/src/main/java/com/android/tools/r8/code/Nop.java
+++ b/src/main/java/com/android/tools/r8/code/Nop.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.code;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
public class Nop extends Format10x {
@@ -33,7 +34,7 @@
// Notice that this must be overridden by the "Nop" subtypes!
@Override
- int internalCompareTo(Instruction other) {
+ int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
return DexCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
}
diff --git a/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java b/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java
index 4ea070c..3d297bb 100644
--- a/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java
@@ -8,11 +8,11 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
import java.util.Arrays;
-import java.util.Comparator;
public class PackedSwitchPayload extends SwitchPayload {
@@ -20,6 +20,10 @@
public final int first_key;
public final /* offset */ int[] targets;
+ private static void specify(StructuralSpecification<PackedSwitchPayload, ?> spec) {
+ spec.withInt(i -> i.size).withInt(i -> i.first_key).withIntArray(i -> i.targets);
+ }
+
public PackedSwitchPayload(int high, BytecodeStream stream) {
super(high, stream);
size = read16BitValue(stream);
@@ -58,11 +62,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- return Comparator.comparingInt((PackedSwitchPayload i) -> i.size)
- .thenComparingInt(i -> first_key)
- .thenComparing(i -> i.targets, ComparatorUtils::compareIntArray)
- .compare(this, (PackedSwitchPayload) other);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (PackedSwitchPayload) other, PackedSwitchPayload::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/ReturnVoid.java b/src/main/java/com/android/tools/r8/code/ReturnVoid.java
index 68cfb51..32d75f8 100644
--- a/src/main/java/com/android/tools/r8/code/ReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/code/ReturnVoid.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.code;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
public class ReturnVoid extends Format10x {
@@ -33,7 +34,7 @@
}
@Override
- final int internalCompareTo(Instruction other) {
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
return DexCompareHelper.compareIdUniquelyDeterminesEquality(this, other);
}
diff --git a/src/main/java/com/android/tools/r8/code/SgetOrSput.java b/src/main/java/com/android/tools/r8/code/SgetOrSput.java
index 4524f8e..499d679 100644
--- a/src/main/java/com/android/tools/r8/code/SgetOrSput.java
+++ b/src/main/java/com/android/tools/r8/code/SgetOrSput.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
abstract class SgetOrSput extends Format21c<DexField> {
@@ -49,7 +50,7 @@
}
@Override
- int internalCompareBBBB(Format21c<?> other) {
- return BBBB.compareTo((DexField) other.BBBB);
+ void internalSubSpecify(StructuralSpecification<Format21c<DexField>, ?> spec) {
+ spec.withItem(i -> i.BBBB);
}
}
diff --git a/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java b/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java
index 1a1b1e9..9dac193e 100644
--- a/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java
@@ -8,11 +8,11 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.ComparatorUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.nio.ShortBuffer;
import java.util.Arrays;
-import java.util.Comparator;
public class SparseSwitchPayload extends SwitchPayload {
@@ -20,6 +20,10 @@
public final int[] keys;
public final /* offset */ int[] targets;
+ private static void specify(StructuralSpecification<SparseSwitchPayload, ?> spec) {
+ spec.withInt(i -> i.size).withIntArray(i -> i.keys).withIntArray(i -> i.targets);
+ }
+
public SparseSwitchPayload(int high, BytecodeStream stream) {
super(high, stream);
size = read16BitValue(stream);
@@ -64,11 +68,8 @@
}
@Override
- final int internalCompareTo(Instruction other) {
- return Comparator.comparingInt((SparseSwitchPayload i) -> i.size)
- .thenComparing(i -> i.keys, ComparatorUtils::compareIntArray)
- .thenComparing(i -> i.targets, ComparatorUtils::compareIntArray)
- .compare(this, (SparseSwitchPayload) other);
+ final int internalAcceptCompareTo(Instruction other, CompareToVisitor visitor) {
+ return visitor.visit(this, (SparseSwitchPayload) other, SparseSwitchPayload::specify);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/dex/Constants.java b/src/main/java/com/android/tools/r8/dex/Constants.java
index e3801e6..dfa8667 100644
--- a/src/main/java/com/android/tools/r8/dex/Constants.java
+++ b/src/main/java/com/android/tools/r8/dex/Constants.java
@@ -140,6 +140,7 @@
public static final String JAVA_LANG_OBJECT_NAME = "java/lang/Object";
public static final String INSTANCE_INITIALIZER_NAME = "<init>";
public static final String CLASS_INITIALIZER_NAME = "<clinit>";
+ public static final String TEMPORARY_INSTANCE_INITIALIZER_PREFIX = "$r8$constructor";
public static final int MAX_NON_JUMBO_INDEX = U16BIT_MAX;
diff --git a/src/main/java/com/android/tools/r8/errors/ExperimentalClassFileVersionDiagnostic.java b/src/main/java/com/android/tools/r8/errors/ExperimentalClassFileVersionDiagnostic.java
new file mode 100644
index 0000000..953afb2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/errors/ExperimentalClassFileVersionDiagnostic.java
@@ -0,0 +1,35 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.errors;
+
+import com.android.tools.r8.Diagnostic;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.position.Position;
+
+public class ExperimentalClassFileVersionDiagnostic implements Diagnostic {
+
+ private final String message;
+ private final Origin origin;
+
+ public ExperimentalClassFileVersionDiagnostic(Origin origin, String message) {
+ this.origin = origin;
+ this.message = message;
+ }
+
+ @Override
+ public Origin getOrigin() {
+ return origin;
+ }
+
+ @Override
+ public Position getPosition() {
+ return Position.UNKNOWN;
+ }
+
+ @Override
+ public String getDiagnosticMessage() {
+ return message;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
index b6588df..ec95ade 100644
--- a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
+++ b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
import com.google.common.collect.Sets;
@@ -135,11 +136,11 @@
return rewrittenClassToFeatureSplitMap;
}
- public ClassToFeatureSplitMap withoutPrunedClasses(Set<DexType> prunedClasses) {
+ public ClassToFeatureSplitMap withoutPrunedItems(PrunedItems prunedItems) {
ClassToFeatureSplitMap classToFeatureSplitMapAfterPruning = new ClassToFeatureSplitMap();
classToFeatureSplitMap.forEach(
(type, featureSplit) -> {
- if (!prunedClasses.contains(type)) {
+ if (!prunedItems.getRemovedClasses().contains(type)) {
classToFeatureSplitMapAfterPruning.classToFeatureSplitMap.put(type, featureSplit);
}
});
diff --git a/src/main/java/com/android/tools/r8/graph/AppServices.java b/src/main/java/com/android/tools/r8/graph/AppServices.java
index 7fe273a..c0c3976 100644
--- a/src/main/java/com/android/tools/r8/graph/AppServices.java
+++ b/src/main/java/com/android/tools/r8/graph/AppServices.java
@@ -26,7 +26,6 @@
import java.io.IOException;
import java.nio.charset.Charset;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -139,11 +138,11 @@
return new AppServices(appView, rewrittenFeatureMappings.build());
}
- public AppServices prunedCopy(Collection<DexType> removedClasses) {
+ public AppServices prunedCopy(PrunedItems prunedItems) {
ImmutableMap.Builder<DexType, Map<FeatureSplit, List<DexType>>> rewrittenServicesBuilder =
ImmutableMap.builder();
for (Entry<DexType, Map<FeatureSplit, List<DexType>>> entry : services.entrySet()) {
- if (removedClasses.contains(entry.getKey())) {
+ if (prunedItems.getRemovedClasses().contains(entry.getKey())) {
continue;
}
ImmutableMap.Builder<FeatureSplit, List<DexType>> prunedFeatureSplitImpls =
@@ -152,7 +151,7 @@
ImmutableList.Builder<DexType> rewrittenServiceImplementationTypesBuilder =
ImmutableList.builder();
for (DexType serviceImplementationType : featureSplitEntry.getValue()) {
- if (!removedClasses.contains(serviceImplementationType)) {
+ if (!prunedItems.getRemovedClasses().contains(serviceImplementationType)) {
rewrittenServiceImplementationTypesBuilder.add(serviceImplementationType);
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index ce2d937..8e0800b 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -22,6 +22,7 @@
import com.android.tools.r8.ir.conversion.MethodProcessingId;
import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
import com.android.tools.r8.ir.optimize.CallSiteOptimizationInfoPropagator;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
import com.android.tools.r8.ir.optimize.info.field.InstanceFieldInitializationInfoFactory;
import com.android.tools.r8.ir.optimize.library.LibraryMemberOptimizer;
import com.android.tools.r8.ir.optimize.library.LibraryMethodSideEffectModelCollection;
@@ -38,8 +39,6 @@
import com.android.tools.r8.utils.ThrowingConsumer;
import com.google.common.base.Predicates;
import com.google.common.collect.ImmutableSet;
-import java.util.Collection;
-import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.Map;
import java.util.Set;
@@ -87,7 +86,7 @@
private HorizontallyMergedClasses horizontallyMergedClasses;
private StaticallyMergedClasses staticallyMergedClasses;
private VerticallyMergedClasses verticallyMergedClasses;
- private EnumValueInfoMapCollection unboxedEnums = EnumValueInfoMapCollection.empty();
+ private EnumDataMap unboxedEnums = EnumDataMap.empty();
// TODO(b/169115389): Remove
private Set<DexMethod> cfByteCodePassThrough = ImmutableSet.of();
@@ -95,7 +94,7 @@
// When input has been (partially) desugared these are the classes which has been library
// desugared. This information is populated in the IR converter.
- private Set<DexProgramClass> alreadyLibraryDesugared = null;
+ private Set<DexType> alreadyLibraryDesugared = null;
private AppView(
T appInfo,
@@ -512,18 +511,18 @@
testing().verticallyMergedClassesConsumer.accept(dexItemFactory(), verticallyMergedClasses);
}
- public EnumValueInfoMapCollection unboxedEnums() {
+ public EnumDataMap unboxedEnums() {
return unboxedEnums;
}
- public void setUnboxedEnums(EnumValueInfoMapCollection unboxedEnums) {
+ public void setUnboxedEnums(EnumDataMap unboxedEnums) {
assert this.unboxedEnums.isEmpty();
this.unboxedEnums = unboxedEnums;
testing().unboxedEnumsConsumer.accept(dexItemFactory(), unboxedEnums);
}
public boolean validateUnboxedEnumsHaveBeenPruned() {
- for (DexType unboxedEnum : unboxedEnums.enumSet()) {
+ for (DexType unboxedEnum : unboxedEnums.getUnboxedEnums()) {
assert appInfo.definitionForWithoutExistenceAssert(unboxedEnum) == null
: "Enum " + unboxedEnum + " has been unboxed but is still in the program.";
assert appInfo().withLiveness().wasPruned(unboxedEnum)
@@ -569,35 +568,17 @@
return !cfByteCodePassThrough.isEmpty();
}
- public void removePrunedClasses(
- DirectMappedDexApplication prunedApp, Set<DexType> removedClasses) {
- removePrunedClasses(prunedApp, removedClasses, Collections.emptySet());
+ public void pruneItems(PrunedItems prunedItems) {
+ pruneItems(prunedItems, withLiveness());
}
- public void removePrunedClasses(
- DirectMappedDexApplication prunedApp,
- Set<DexType> removedClasses,
- Collection<DexMethod> methodsToKeepForConfigurationDebugging) {
- assert enableWholeProgramOptimizations();
- assert appInfo().hasLiveness();
- removePrunedClasses(
- prunedApp, removedClasses, methodsToKeepForConfigurationDebugging, withLiveness());
- }
-
- private static void removePrunedClasses(
- DirectMappedDexApplication prunedApp,
- Set<DexType> removedClasses,
- Collection<DexMethod> methodsToKeepForConfigurationDebugging,
- AppView<AppInfoWithLiveness> appView) {
- if (removedClasses.isEmpty() && !appView.options().configurationDebugging) {
- assert appView.appInfo.app() == prunedApp;
+ private static void pruneItems(PrunedItems prunedItems, AppView<AppInfoWithLiveness> appView) {
+ if (!prunedItems.hasRemovedClasses() && !appView.options().configurationDebugging) {
+ assert appView.appInfo().app() == prunedItems.getPrunedApp();
return;
}
- appView.setAppInfo(
- appView
- .appInfo()
- .prunedCopyFrom(prunedApp, removedClasses, methodsToKeepForConfigurationDebugging));
- appView.setAppServices(appView.appServices().prunedCopy(removedClasses));
+ appView.setAppInfo(appView.appInfo().prunedCopyFrom(prunedItems));
+ appView.setAppServices(appView.appServices().prunedCopy(prunedItems));
}
public void rewriteWithLens(NonIdentityGraphLens lens) {
@@ -661,7 +642,7 @@
});
}
- public void setAlreadyLibraryDesugared(Set<DexProgramClass> alreadyLibraryDesugared) {
+ public void setAlreadyLibraryDesugared(Set<DexType> alreadyLibraryDesugared) {
assert this.alreadyLibraryDesugared == null;
this.alreadyLibraryDesugared = alreadyLibraryDesugared;
}
@@ -671,6 +652,6 @@
return false;
}
assert alreadyLibraryDesugared != null;
- return alreadyLibraryDesugared.contains(clazz);
+ return alreadyLibraryDesugared.contains(clazz.getType());
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java b/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
index 887f10d..559d2f2 100644
--- a/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/AppliedGraphLens.java
@@ -6,7 +6,8 @@
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
import com.android.tools.r8.utils.MapUtils;
-import com.android.tools.r8.utils.collections.BidirectionalManyToOneMap;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneMap;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
@@ -25,8 +26,8 @@
*/
public final class AppliedGraphLens extends NonIdentityGraphLens {
- private final BidirectionalManyToOneMap<DexType, DexType> renamedTypeNames =
- new BidirectionalManyToOneMap<>();
+ private final MutableBidirectionalManyToOneMap<DexType, DexType> renamedTypeNames =
+ new BidirectionalManyToOneHashMap<>();
private final BiMap<DexField, DexField> originalFieldSignatures = HashBiMap.create();
private final BiMap<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create();
@@ -102,11 +103,8 @@
@Override
public Iterable<DexType> getOriginalTypes(DexType type) {
- Set<DexType> originalTypes = renamedTypeNames.getKeysOrNull(type);
- if (originalTypes == null) {
- return ImmutableList.of(type);
- }
- return originalTypes;
+ Set<DexType> originalTypes = renamedTypeNames.getKeys(type);
+ return originalTypes.isEmpty() ? ImmutableList.of(type) : originalTypes;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
index fbd5e7a..719e2d6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClassAndMember.java
@@ -39,6 +39,10 @@
return definition;
}
+ public DexString getName() {
+ return getReference().getName();
+ }
+
public R getReference() {
return definition.getReference();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index ab974b3..2e42ccf 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -3,8 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import static com.android.tools.r8.utils.ComparatorUtils.arrayComparator;
-
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.ReturnVoid;
import com.android.tools.r8.code.SwitchPayload;
@@ -22,13 +20,16 @@
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.utils.ComparatorUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.structural.Equatable;
+import com.android.tools.r8.utils.structural.HashCodeVisitor;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralMapping;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import com.google.common.base.Strings;
import it.unimi.dsi.fastutil.ints.Int2IntMap;
import java.util.Arrays;
import java.util.Collections;
-import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
@@ -36,7 +37,7 @@
import java.util.Set;
// DexCode corresponds to code item in dalvik/dex-format.html
-public class DexCode extends Code implements Comparable<DexCode> {
+public class DexCode extends Code implements StructuralItem<DexCode> {
static final String FAKE_THIS_PREFIX = "_";
static final String FAKE_THIS_SUFFIX = "this";
@@ -52,6 +53,16 @@
private DexDebugInfo debugInfo;
private DexDebugInfoForWriting debugInfoForWriting;
+ private static void specify(StructuralSpecification<DexCode, ?> spec) {
+ spec.withInt(c -> c.registerSize)
+ .withInt(c -> c.incomingRegisterSize)
+ .withInt(c -> c.outgoingRegisterSize)
+ .withItemArray(c -> c.tries)
+ .withItemArray(c -> c.handlers)
+ .withNullableItem(c -> c.debugInfo)
+ .withItemArray(c -> c.instructions);
+ }
+
public DexCode(
int registerSize,
int insSize,
@@ -73,6 +84,16 @@
hashCode(); // Cache the hash code eagerly.
}
+ @Override
+ public DexCode self() {
+ return this;
+ }
+
+ @Override
+ public StructuralMapping<DexCode> getStructuralMapping() {
+ return DexCode::specify;
+ }
+
public DexCode withoutThisParameter() {
// Note that we assume the original code has a register associated with 'this'
// argument of the (former) instance method. We also assume (but do not check)
@@ -183,26 +204,8 @@
}
@Override
- public int compareTo(DexCode other) {
- if (this == other) {
- return 0;
- }
- int diff =
- Comparator.comparingInt((DexCode c) -> c.incomingRegisterSize)
- .thenComparingInt(c -> c.registerSize)
- .thenComparingInt(c -> c.outgoingRegisterSize)
- .thenComparing(c -> c.tries, arrayComparator())
- .thenComparing(c -> c.handlers, arrayComparator())
- .thenComparing(c -> c.debugInfo, Comparator.nullsFirst(DexDebugInfo::compareTo))
- .thenComparing((DexCode c) -> c.instructions, arrayComparator())
- .compare(this, other);
- assert (diff == 0) == (0 == toString().compareTo(other.toString()));
- return diff;
- }
-
- @Override
public boolean computeEquals(Object other) {
- return other instanceof DexCode && compareTo((DexCode) other) == 0;
+ return Equatable.equalsImpl(this, other);
}
@Override
@@ -453,7 +456,7 @@
return last.getOffset() + last.getSize();
}
- public static class Try extends DexItem implements Comparable<Try> {
+ public static class Try extends DexItem implements StructuralItem<Try> {
public static final int NO_INDEX = -1;
@@ -462,6 +465,13 @@
public /* offset */ int instructionCount;
public int handlerIndex;
+ private static void specify(StructuralSpecification<Try, ?> spec) {
+ // The handler offset is the offset given by the dex input and does not determine the item.
+ spec.withInt(t -> t.startAddress)
+ .withInt(t -> t.instructionCount)
+ .withInt(t -> t.handlerIndex);
+ }
+
public Try(int startAddress, int instructionCount, int handlerOffset) {
this.startAddress = startAddress;
this.instructionCount = instructionCount;
@@ -469,6 +479,16 @@
this.handlerIndex = NO_INDEX;
}
+ @Override
+ public Try self() {
+ return this;
+ }
+
+ @Override
+ public StructuralMapping<Try> getStructuralMapping() {
+ return Try::specify;
+ }
+
public void setHandlerIndex(Int2IntMap map) {
handlerIndex = map.get(handlerOffset);
}
@@ -480,18 +500,7 @@
@Override
public boolean equals(Object other) {
- return other instanceof Try && compareTo((Try) other) == 0;
- }
-
- @Override
- public int compareTo(Try other) {
- if (this == other) {
- return 0;
- }
- return ComparatorUtils.compareInts(
- startAddress, other.startAddress,
- instructionCount, other.instructionCount,
- handlerIndex, other.handlerIndex);
+ return Equatable.equalsImpl(this, other);
}
@Override
@@ -512,36 +521,40 @@
}
- public static class TryHandler extends DexItem implements Comparable<TryHandler> {
+ public static class TryHandler extends DexItem implements StructuralItem<TryHandler> {
public static final int NO_HANDLER = -1;
public final TypeAddrPair[] pairs;
public final /* offset */ int catchAllAddr;
+ private static void specify(StructuralSpecification<TryHandler, ?> spec) {
+ spec.withInt(h -> h.catchAllAddr).withItemArray(h -> h.pairs);
+ }
+
public TryHandler(TypeAddrPair[] pairs, int catchAllAddr) {
this.pairs = pairs;
this.catchAllAddr = catchAllAddr;
}
@Override
+ public TryHandler self() {
+ return this;
+ }
+
+ @Override
+ public StructuralMapping<TryHandler> getStructuralMapping() {
+ return TryHandler::specify;
+ }
+
+ @Override
public int hashCode() {
- return catchAllAddr + Arrays.hashCode(pairs) * 7;
+ return HashCodeVisitor.run(this);
}
@Override
public boolean equals(Object other) {
- return other instanceof TryHandler && compareTo((TryHandler) other) == 0;
- }
-
- @Override
- public int compareTo(TryHandler other) {
- if (this == other) {
- return 0;
- }
- return Comparator.comparingInt((TryHandler h) -> h.catchAllAddr)
- .thenComparing(h -> h.pairs, arrayComparator())
- .compare(this, other);
+ return Equatable.equalsImpl(this, other);
}
public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
@@ -576,16 +589,30 @@
return builder.toString();
}
- public static class TypeAddrPair extends DexItem implements Comparable<TypeAddrPair> {
+ public static class TypeAddrPair extends DexItem implements StructuralItem<TypeAddrPair> {
private final DexType type;
public final /* offset */ int addr;
+ private static void specify(StructuralSpecification<TypeAddrPair, ?> spec) {
+ spec.withItem(p -> p.type).withInt(p -> p.addr);
+ }
+
public TypeAddrPair(DexType type, int addr) {
this.type = type;
this.addr = addr;
}
+ @Override
+ public TypeAddrPair self() {
+ return this;
+ }
+
+ @Override
+ public StructuralMapping<TypeAddrPair> getStructuralMapping() {
+ return TypeAddrPair::specify;
+ }
+
public DexType getType() {
return type;
}
@@ -612,17 +639,7 @@
@Override
public boolean equals(Object other) {
- return other instanceof TypeAddrPair && compareTo((TypeAddrPair) other) == 0;
- }
-
- @Override
- public int compareTo(TypeAddrPair other) {
- if (this == other) {
- return 0;
- }
- return Comparator.comparingInt((TypeAddrPair p) -> p.addr)
- .thenComparing(p -> p.type)
- .compare(this, other);
+ return Equatable.equalsImpl(this, other);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
index 16842b0..9dba226 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
@@ -7,11 +7,16 @@
import com.android.tools.r8.dex.DebugBytecodeWriter;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
+import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.code.Position;
-import java.util.Comparator;
+import com.android.tools.r8.utils.structural.CompareToVisitor;
+import com.android.tools.r8.utils.structural.HashingVisitor;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralMapping;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.Objects;
-public abstract class DexDebugEvent extends DexItem implements Comparable<DexDebugEvent> {
+public abstract class DexDebugEvent extends DexItem implements StructuralItem<DexDebugEvent> {
// Compare ID(s) for virtual debug events.
private static final int DBG_SET_INLINE_FRAME_COMPARE_ID = Constants.DBG_LAST_SPECIAL + 1;
@@ -41,15 +46,30 @@
abstract int getCompareToId();
- abstract int internalCompareTo(DexDebugEvent other);
+ abstract int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor);
+
+ abstract void internalAcceptHashing(HashingVisitor visitor);
@Override
- public final int compareTo(DexDebugEvent other) {
- if (this == other) {
- return 0;
- }
- int diff = Integer.compare(getCompareToId(), other.getCompareToId());
- return diff != 0 ? diff : internalCompareTo(other);
+ public DexDebugEvent self() {
+ return this;
+ }
+
+ @Override
+ public StructuralMapping<DexDebugEvent> getStructuralMapping() {
+ throw new Unreachable();
+ }
+
+ @Override
+ public final int acceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
+ int diff = visitor.visitInt(getCompareToId(), other.getCompareToId());
+ return diff != 0 ? diff : internalAcceptCompareTo(other, visitor);
+ }
+
+ @Override
+ public final void acceptHashing(HashingVisitor visitor) {
+ visitor.visitInt(getCompareToId());
+ internalAcceptHashing(visitor);
}
public abstract void writeOn(DebugBytecodeWriter writer, ObjectToOffsetMapping mapping);
@@ -102,8 +122,13 @@
}
@Override
- int internalCompareTo(DexDebugEvent other) {
- return Integer.compare(delta, ((AdvancePC) other).delta);
+ int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
+ return visitor.visitInt(delta, ((AdvancePC) other).delta);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitInt(delta);
}
}
@@ -139,10 +164,15 @@
}
@Override
- int internalCompareTo(DexDebugEvent other) {
+ int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
assert other instanceof SetPrologueEnd;
return 0;
}
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ // Nothing to hash as the ID has already been hashed.
+ }
}
@@ -177,10 +207,15 @@
}
@Override
- int internalCompareTo(DexDebugEvent other) {
+ int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
assert other instanceof SetEpilogueBegin;
return 0;
}
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ // Nothing to hash as the ID has already been hashed.
+ }
}
public static class AdvanceLine extends DexDebugEvent {
@@ -219,8 +254,13 @@
}
@Override
- int internalCompareTo(DexDebugEvent other) {
- return Integer.compare(delta, ((AdvanceLine) other).delta);
+ int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
+ return visitor.visitInt(delta, ((AdvanceLine) other).delta);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitInt(delta);
}
}
@@ -231,6 +271,13 @@
final DexType type;
final DexString signature;
+ private static void spec(StructuralSpecification<StartLocal, ?> spec) {
+ spec.withInt(e -> e.registerNum)
+ .withItem(e -> e.name)
+ .withItem(e -> e.type)
+ .withNullableItem(e -> e.signature);
+ }
+
public StartLocal(
int registerNum,
DexString name,
@@ -298,12 +345,13 @@
}
@Override
- int internalCompareTo(DexDebugEvent other) {
- return Comparator.comparingInt((StartLocal e) -> e.registerNum)
- .thenComparing(e -> e.name)
- .thenComparing(e -> e.type)
- .thenComparing(e -> e.signature, Comparator.nullsFirst(DexString::compareTo))
- .compare(this, (StartLocal) other);
+ int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
+ return visitor.visit(this, (StartLocal) other, StartLocal::spec);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visit(this, StartLocal::spec);
}
}
@@ -343,8 +391,13 @@
}
@Override
- int internalCompareTo(DexDebugEvent other) {
- return Integer.compare(registerNum, ((EndLocal) other).registerNum);
+ int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
+ return visitor.visitInt(registerNum, ((EndLocal) other).registerNum);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitInt(registerNum);
}
}
@@ -384,8 +437,13 @@
}
@Override
- int internalCompareTo(DexDebugEvent other) {
- return Integer.compare(registerNum, ((RestartLocal) other).registerNum);
+ int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
+ return visitor.visitInt(registerNum, ((RestartLocal) other).registerNum);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitInt(registerNum);
}
}
@@ -430,8 +488,13 @@
}
@Override
- int internalCompareTo(DexDebugEvent other) {
- return fileName.compareTo(((SetFile) other).fileName);
+ int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
+ return fileName.acceptCompareTo(((SetFile) other).fileName, visitor);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ fileName.acceptHashing(visitor);
}
}
@@ -440,6 +503,10 @@
final DexMethod callee;
final Position caller;
+ private static void specify(StructuralSpecification<SetInlineFrame, ?> spec) {
+ spec.withItem(e -> e.callee).withNullableItem(e -> e.caller);
+ }
+
SetInlineFrame(DexMethod callee, Position caller) {
assert callee != null;
this.callee = callee;
@@ -472,10 +539,13 @@
}
@Override
- int internalCompareTo(DexDebugEvent other) {
- return Comparator.comparing((SetInlineFrame e) -> e.callee, DexMethod::compareTo)
- .thenComparing(e -> e.caller, Comparator.nullsFirst(Position::compareTo))
- .compare(this, (SetInlineFrame) other);
+ int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
+ return visitor.visit(this, (SetInlineFrame) other, SetInlineFrame::specify);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visit(this, SetInlineFrame::specify);
}
@Override
@@ -540,8 +610,13 @@
}
@Override
- int internalCompareTo(DexDebugEvent other) {
- return Integer.compare(value, ((Default) other).value);
+ int internalAcceptCompareTo(DexDebugEvent other, CompareToVisitor visitor) {
+ return visitor.visitInt(value, ((Default) other).value);
+ }
+
+ @Override
+ void internalAcceptHashing(HashingVisitor visitor) {
+ visitor.visitInt(value);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
index 5bfbd8d..75588f6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
@@ -5,17 +5,25 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
-import com.android.tools.r8.utils.ComparatorUtils;
+import com.android.tools.r8.utils.structural.Equatable;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralMapping;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.Arrays;
-import java.util.Comparator;
import java.util.List;
-public class DexDebugInfo extends CachedHashValueDexItem implements Comparable<DexDebugInfo> {
+public class DexDebugInfo extends CachedHashValueDexItem implements StructuralItem<DexDebugInfo> {
public final int startLine;
public final DexString[] parameters;
public DexDebugEvent[] events;
+ private static void specify(StructuralSpecification<DexDebugInfo, ?> spec) {
+ spec.withInt(d -> d.startLine)
+ .withItemArrayAllowingNullMembers(d -> d.parameters)
+ .withItemArray(d -> d.events);
+ }
+
public DexDebugInfo(int startLine, DexString[] parameters, DexDebugEvent[] events) {
assert startLine >= 0;
this.startLine = startLine;
@@ -26,6 +34,16 @@
hashCode();
}
+ @Override
+ public DexDebugInfo self() {
+ return this;
+ }
+
+ @Override
+ public StructuralMapping<DexDebugInfo> getStructuralMapping() {
+ return DexDebugInfo::specify;
+ }
+
public List<DexDebugEntry> computeEntries(DexMethod method) {
DexDebugEntryBuilder builder = new DexDebugEntryBuilder(startLine, method);
for (DexDebugEvent event : events) {
@@ -43,20 +61,7 @@
@Override
public final boolean computeEquals(Object other) {
- return other instanceof DexDebugInfo && compareTo((DexDebugInfo) other) == 0;
- }
-
- @Override
- public final int compareTo(DexDebugInfo other) {
- if (this == other) {
- return 0;
- }
- return Comparator.comparingInt((DexDebugInfo i) -> i.startLine)
- .thenComparing(
- i -> i.parameters,
- ComparatorUtils.arrayComparator(Comparator.nullsFirst(DexString::compareTo)))
- .thenComparing(i -> i.events, ComparatorUtils.arrayComparator())
- .compare(this, other);
+ return Equatable.equalsImpl(this, other);
}
public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 7d807e9..bcbc160 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -514,6 +514,24 @@
return accessFlags.isConstructor() && !accessFlags.isStatic();
}
+ /**
+ * Returns true for (private instance) methods that have been created as a result of class merging
+ * and will be force-inlined into an instance initializer on the enclosing class.
+ */
+ public boolean willBeInlinedIntoInstanceInitializer(DexItemFactory dexItemFactory) {
+ checkIfObsolete();
+ if (getName().startsWith(dexItemFactory.temporaryConstructorMethodPrefix)) {
+ assert isPrivate();
+ assert !isStatic();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isOrWillBeInlinedIntoInstanceInitializer(DexItemFactory dexItemFactory) {
+ return isInstanceInitializer() || willBeInlinedIntoInstanceInitializer(dexItemFactory);
+ }
+
public boolean isDefaultInitializer() {
checkIfObsolete();
return isInstanceInitializer() && method.proto.parameters.isEmpty();
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 dac5b16..a93000e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -188,7 +188,6 @@
public final DexString convertMethodName = createString("convert");
public final DexString wrapperFieldName = createString("wrappedValue");
- public final DexString initMethodName = createString("<init>");
public final DexString getClassMethodName = createString("getClass");
public final DexString finalizeMethodName = createString("finalize");
@@ -290,6 +289,8 @@
public final DexString constructorMethodName = createString(Constants.INSTANCE_INITIALIZER_NAME);
public final DexString classConstructorMethodName =
createString(Constants.CLASS_INITIALIZER_NAME);
+ public final DexString temporaryConstructorMethodPrefix =
+ createString(Constants.TEMPORARY_INSTANCE_INITIALIZER_PREFIX);
public final DexString thisName = createString("this");
public final DexString enumValuesFieldName = createString("$VALUES");
@@ -1134,6 +1135,8 @@
public final DexMethod requireNonNull;
public final DexMethod requireNonNullWithMessage;
public final DexMethod requireNonNullWithMessageSupplier;
+ public final DexMethod toStringWithObject =
+ createMethod(objectsType, createProto(stringType, objectType), "toString");
private ObjectsMethods() {
DexString requireNonNullMethodName = createString("requireNonNull");
@@ -1357,7 +1360,7 @@
public final DexMethod initWithMessage =
createMethod(
- illegalArgumentExceptionType, createProto(voidType, stringType), initMethodName);
+ illegalArgumentExceptionType, createProto(voidType, stringType), constructorMethodName);
}
/**
@@ -1548,6 +1551,8 @@
public final DexMethod toString;
private final Set<DexMethod> appendMethods;
+ private final Set<DexMethod> appendPrimitiveMethods;
+
private StringBuildingMethods(DexType receiver) {
DexString append = createString("append");
@@ -1566,7 +1571,6 @@
appendObject = createMethod(receiver, createProto(receiver, objectType), append);
appendString = createMethod(receiver, createProto(receiver, stringType), append);
appendStringBuffer = createMethod(receiver, createProto(receiver, stringBufferType), append);
-
charSequenceConstructor =
createMethod(receiver, createProto(voidType, charSequenceType), constructorMethodName);
defaultConstructor = createMethod(receiver, createProto(voidType), constructorMethodName);
@@ -1591,6 +1595,9 @@
appendObject,
appendString,
appendStringBuffer);
+ appendPrimitiveMethods =
+ ImmutableSet.of(
+ appendBoolean, appendChar, appendInt, appendDouble, appendFloat, appendLong);
constructorMethods =
ImmutableSet.of(
charSequenceConstructor, defaultConstructor, intConstructor, stringConstructor);
@@ -1602,12 +1609,29 @@
return appendMethods.contains(method);
}
+ public boolean isAppendObjectMethod(DexMethod method) {
+ return method == appendObject;
+ }
+
+ public boolean isAppendPrimitiveMethod(DexMethod method) {
+ return appendPrimitiveMethods.contains(method);
+ }
+
+ public boolean isAppendStringMethod(DexMethod method) {
+ return method == appendString;
+ }
+
+ public boolean isConstructorMethod(DexMethod method) {
+ return constructorMethods.contains(method);
+ }
+
public boolean constructorInvokeIsSideEffectFree(InvokeMethod invoke) {
DexMethod invokedMethod = invoke.getInvokedMethod();
if (invokedMethod == charSequenceConstructor) {
- // NullPointerException - if seq is null.
- Value seqValue = invoke.inValues().get(1);
- return !seqValue.getType().isNullable();
+ // Performs callbacks on the given CharSequence, which may have side effects.
+ TypeElement charSequenceType = invoke.getArgument(1).getType();
+ return charSequenceType.isClassType()
+ && charSequenceType.asClassType().getClassType() == stringType;
}
if (invokedMethod == defaultConstructor) {
@@ -1926,6 +1950,10 @@
holder);
}
+ public DexMethod createClassInitializer(DexType holder) {
+ return createMethod(holder, createProto(voidType), classConstructorMethodName);
+ }
+
public DexMethod createInstanceInitializerWithFreshProto(
DexMethod method, List<DexType> extraTypes, Predicate<DexMethod> isFresh) {
assert method.isInstanceInitializer(this);
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index c91ffdf..8ab4935 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -58,6 +58,10 @@
return proto.parameters;
}
+ public DexProto getProto() {
+ return proto;
+ }
+
public DexType getReturnType() {
return proto.returnType;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 3e92e74..0faef1b 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -756,4 +756,8 @@
public long getChecksum() {
return checksumSupplier.getChecksum(this);
}
+
+ public ChecksumSupplier getChecksumSupplier() {
+ return checksumSupplier;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexReference.java b/src/main/java/com/android/tools/r8/graph/DexReference.java
index 8a59614..77976f1 100644
--- a/src/main/java/com/android/tools/r8/graph/DexReference.java
+++ b/src/main/java/com/android/tools/r8/graph/DexReference.java
@@ -73,19 +73,4 @@
assert isDexMethod();
return 3;
}
-
- public int referenceCompareTo(DexReference o) {
- int typeDiff = referenceTypeOrder() - o.referenceTypeOrder();
- if (typeDiff != 0) {
- return typeDiff;
- }
- if (isDexType()) {
- return asDexType().compareTo(o.asDexType());
- }
- if (isDexField()) {
- return asDexField().compareTo(o.asDexField());
- }
- assert isDexMethod();
- return asDexMethod().compareTo(o.asDexMethod());
- }
}
diff --git a/src/main/java/com/android/tools/r8/graph/EnumValueInfoMapCollection.java b/src/main/java/com/android/tools/r8/graph/EnumValueInfoMapCollection.java
deleted file mode 100644
index 362ff7c..0000000
--- a/src/main/java/com/android/tools/r8/graph/EnumValueInfoMapCollection.java
+++ /dev/null
@@ -1,139 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.graph;
-
-import com.google.common.collect.ImmutableMap;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Set;
-import java.util.function.BiConsumer;
-
-public class EnumValueInfoMapCollection {
-
- public static EnumValueInfoMapCollection empty() {
- return new EnumValueInfoMapCollection(ImmutableMap.of());
- }
-
- private final Map<DexType, EnumValueInfoMap> maps;
-
- private EnumValueInfoMapCollection(Map<DexType, EnumValueInfoMap> maps) {
- this.maps = maps;
- }
-
- public EnumValueInfoMap getEnumValueInfoMap(DexType type) {
- return maps.get(type);
- }
-
- public boolean isEmpty() {
- return maps.isEmpty();
- }
-
- public boolean containsEnum(DexType type) {
- return maps.containsKey(type);
- }
-
- public Set<DexType> enumSet() {
- return maps.keySet();
- }
-
- public EnumValueInfoMapCollection rewrittenWithLens(GraphLens lens) {
- Builder builder = builder();
- maps.forEach(
- (type, map) -> {
- DexType dexType = lens.lookupType(type);
- // Enum unboxing may have changed the type to int type.
- // Do not keep the map for such enums.
- if (!dexType.isPrimitiveType()) {
- builder.put(dexType, map.rewrittenWithLens(lens));
- }
- });
- return builder.build();
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- public static class Builder {
-
- private ImmutableMap.Builder<DexType, EnumValueInfoMap> builder;
-
- public Builder put(DexType type, EnumValueInfoMap map) {
- if (builder == null) {
- builder = ImmutableMap.builder();
- }
- builder.put(type, map);
- return this;
- }
-
- public EnumValueInfoMapCollection build() {
- if (builder == null) {
- return empty();
- }
- return new EnumValueInfoMapCollection(builder.build());
- }
- }
-
- public static final class EnumValueInfoMap {
-
- private final LinkedHashMap<DexField, EnumValueInfo> map;
-
- public EnumValueInfoMap(LinkedHashMap<DexField, EnumValueInfo> map) {
- this.map = map;
- }
-
- public Set<DexField> enumValues() {
- return map.keySet();
- }
-
- public int size() {
- return map.size();
- }
-
- public boolean hasEnumValueInfo(DexField field) {
- return map.containsKey(field);
- }
-
- public EnumValueInfo getEnumValueInfo(DexField field) {
- return map.get(field);
- }
-
- public void forEach(BiConsumer<DexField, EnumValueInfo> consumer) {
- map.forEach(consumer);
- }
-
- EnumValueInfoMap rewrittenWithLens(GraphLens lens) {
- LinkedHashMap<DexField, EnumValueInfo> rewritten = new LinkedHashMap<>();
- map.forEach(
- (field, valueInfo) ->
- rewritten.put(lens.lookupField(field), valueInfo.rewrittenWithLens(lens)));
- return new EnumValueInfoMap(rewritten);
- }
- }
-
- public static final class EnumValueInfo {
-
- // The anonymous subtype of this specific value or the enum type.
- public final DexType type;
- public final int ordinal;
-
- public EnumValueInfo(DexType type, int ordinal) {
- this.type = type;
- this.ordinal = ordinal;
- }
-
- public int convertToInt() {
- return ordinal + 1;
- }
-
- EnumValueInfo rewrittenWithLens(GraphLens lens) {
- DexType newType = lens.lookupType(type);
- if (type == newType) {
- return this;
- }
- return new EnumValueInfo(newType, ordinal);
- }
- }
-}
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java
index 5a10844..0e3d784 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -4,9 +4,11 @@
package com.android.tools.r8.graph;
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+import static com.android.tools.r8.horizontalclassmerging.ClassMerger.CLASS_ID_FIELD_NAME;
+import static com.android.tools.r8.ir.desugar.LambdaRewriter.LAMBDA_CLASS_NAME_PREFIX;
+import static com.android.tools.r8.ir.desugar.LambdaRewriter.LAMBDA_INSTANCE_FIELD_NAME;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.horizontalclassmerging.ClassMerger;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
@@ -15,10 +17,12 @@
import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.collections.BidirectionalManyToManyRepresentativeMap;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneRepresentativeMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
@@ -32,6 +36,7 @@
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Function;
import java.util.function.Predicate;
+import java.util.stream.Collectors;
/**
* A GraphLens implements a virtual view on top of the graph, used to delay global rewrites until
@@ -65,6 +70,10 @@
return reference;
}
+ public R getRewrittenReference(BidirectionalManyToOneRepresentativeMap<R, R> rewritings) {
+ return rewritings.getOrDefault(reference, reference);
+ }
+
public R getRewrittenReference(Map<R, R> rewritings) {
return rewritings.getOrDefault(reference, reference);
}
@@ -77,6 +86,11 @@
return reboundReference;
}
+ public R getRewrittenReboundReference(
+ BidirectionalManyToOneRepresentativeMap<R, R> rewritings) {
+ return rewritings.getOrDefault(reboundReference, reboundReference);
+ }
+
public R getRewrittenReboundReference(Map<R, R> rewritings) {
return rewritings.getOrDefault(reboundReference, reboundReference);
}
@@ -228,10 +242,10 @@
protected final Map<DexType, DexType> typeMap = new IdentityHashMap<>();
protected final Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>();
- protected final Map<DexField, DexField> fieldMap = new IdentityHashMap<>();
+ protected final MutableBidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap =
+ new BidirectionalManyToOneRepresentativeHashMap<>();
- protected final BiMap<DexField, DexField> originalFieldSignatures = HashBiMap.create();
- protected final BidirectionalOneToOneHashMap<DexMethod, DexMethod> originalMethodSignatures =
+ protected final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures =
new BidirectionalOneToOneHashMap<>();
public void map(DexType from, DexType to) {
@@ -248,13 +262,6 @@
methodMap.put(from, to);
}
- public void map(DexField from, DexField to) {
- if (from == to) {
- return;
- }
- fieldMap.put(from, to);
- }
-
public void move(DexMethod from, DexMethod to) {
if (from == to) {
return;
@@ -268,7 +275,6 @@
return;
}
fieldMap.put(from, to);
- originalFieldSignatures.put(to, from);
}
public GraphLens build(DexItemFactory dexItemFactory) {
@@ -283,7 +289,6 @@
typeMap,
methodMap,
fieldMap,
- originalFieldSignatures,
originalMethodSignatures,
previousLens,
dexItemFactory);
@@ -611,21 +616,14 @@
continue;
}
for (DexEncodedField field : clazz.fields()) {
- // The field $r8$clinitField may be synthesized by R8 in order to trigger the initialization
- // of the enclosing class. It is not present in the input, and therefore we do not require
- // that it can be mapped back to the original program.
- if (field.field.match(dexItemFactory.objectMembers.clinitField)) {
- continue;
- }
-
- // TODO(b/167947782): Should be a general check to see if the field is D8/R8 synthesized.
- if (field.getReference().name.toSourceString().equals(ClassMerger.CLASS_ID_FIELD_NAME)) {
- continue;
- }
-
- DexField originalField = getOriginalFieldSignature(field.field);
+ // Fields synthesized by R8 are not present in the input, and therefore we do not require
+ // that they can be mapped back to the original program.
+ DexField originalField = getOriginalFieldSignature(field.getReference());
assert originalFields.contains(originalField)
- : "Unable to map field `" + field.field.toSourceString() + "` back to original program";
+ || isD8R8SynthesizedField(originalField, dexItemFactory)
+ : "Unable to map field `"
+ + field.getReference().toSourceString()
+ + "` back to original program";
}
for (DexEncodedMethod method : clazz.methods()) {
if (method.isD8R8Synthesized()) {
@@ -640,6 +638,22 @@
return true;
}
+ private boolean isD8R8SynthesizedField(DexField field, DexItemFactory dexItemFactory) {
+ // TODO(b/167947782): Should be a general check to see if the field is D8/R8 synthesized
+ // instead of relying on field names.
+ if (field.match(dexItemFactory.objectMembers.clinitField)) {
+ return true;
+ }
+ if (field.getName().toSourceString().equals(CLASS_ID_FIELD_NAME)) {
+ return true;
+ }
+ if (field.getHolderType().toSourceString().contains(LAMBDA_CLASS_NAME_PREFIX)
+ && field.getName().toSourceString().equals(LAMBDA_INSTANCE_FIELD_NAME)) {
+ return true;
+ }
+ return false;
+ }
+
public abstract static class NonIdentityGraphLens extends GraphLens {
private final DexItemFactory dexItemFactory;
@@ -963,11 +977,10 @@
protected final Map<DexType, DexType> typeMap;
protected final Map<DexMethod, DexMethod> methodMap;
- protected final Map<DexField, DexField> fieldMap;
+ protected final BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap;
- // Maps that store the original signature of fields and methods that have been affected, for
- // example, by vertical class merging. Needed to generate a correct Proguard map in the end.
- protected final BiMap<DexField, DexField> originalFieldSignatures;
+ // Map that store the original signature of methods that have been affected, for example, by
+ // vertical class merging. Needed to generate a correct Proguard map in the end.
protected BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod>
originalMethodSignatures;
@@ -980,8 +993,7 @@
public NestedGraphLens(
Map<DexType, DexType> typeMap,
Map<DexMethod, DexMethod> methodMap,
- Map<DexField, DexField> fieldMap,
- BiMap<DexField, DexField> originalFieldSignatures,
+ BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap,
BidirectionalManyToManyRepresentativeMap<DexMethod, DexMethod> originalMethodSignatures,
GraphLens previousLens,
DexItemFactory dexItemFactory) {
@@ -993,7 +1005,6 @@
this.typeMap = typeMap.isEmpty() ? null : typeMap;
this.methodMap = methodMap;
this.fieldMap = fieldMap;
- this.originalFieldSignatures = originalFieldSignatures;
this.originalMethodSignatures = originalMethodSignatures;
this.dexItemFactory = dexItemFactory;
}
@@ -1022,10 +1033,7 @@
@Override
public DexField getOriginalFieldSignature(DexField field) {
- DexField originalField =
- originalFieldSignatures != null
- ? originalFieldSignatures.getOrDefault(field, field)
- : field;
+ DexField originalField = fieldMap.getRepresentativeKeyOrDefault(field, field);
return getPrevious().getOriginalFieldSignature(originalField);
}
@@ -1038,9 +1046,7 @@
@Override
public DexField getRenamedFieldSignature(DexField originalField) {
DexField renamedField = getPrevious().getRenamedFieldSignature(originalField);
- return originalFieldSignatures != null
- ? originalFieldSignatures.inverse().getOrDefault(renamedField, renamedField)
- : renamedField;
+ return fieldMap.getOrDefault(renamedField, renamedField);
}
@Override
@@ -1221,10 +1227,15 @@
builder.append(entry.getKey().toSourceString()).append(" -> ");
builder.append(entry.getValue().toSourceString()).append(System.lineSeparator());
}
- for (Map.Entry<DexField, DexField> entry : fieldMap.entrySet()) {
- builder.append(entry.getKey().toSourceString()).append(" -> ");
- builder.append(entry.getValue().toSourceString()).append(System.lineSeparator());
- }
+ fieldMap.forEachManyToOneMapping(
+ (keys, value) -> {
+ builder.append(
+ keys.stream()
+ .map(DexField::toSourceString)
+ .collect(Collectors.joining("," + System.lineSeparator())));
+ builder.append(" -> ");
+ builder.append(value.toSourceString()).append(System.lineSeparator());
+ });
builder.append(getPrevious().toString());
return builder.toString();
}
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 0902a45..fabdde7 100644
--- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
+++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java
@@ -57,12 +57,12 @@
import java.util.function.Consumer;
import java.util.zip.CRC32;
import org.objectweb.asm.AnnotationVisitor;
-import org.objectweb.asm.Attribute;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.RecordComponentVisitor;
import org.objectweb.asm.Type;
import org.objectweb.asm.TypePath;
@@ -300,6 +300,17 @@
}
@Override
+ public RecordComponentVisitor visitRecordComponent(
+ String name, String descriptor, String signature) {
+ throw new CompilationError("Records are not supported", origin);
+ }
+
+ @Override
+ public void visitPermittedSubclass(String permittedSubclass) {
+ throw new CompilationError("Sealed classes are not supported", origin);
+ }
+
+ @Override
public void visit(
int rawVersion,
int access,
@@ -311,6 +322,9 @@
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);
@@ -400,11 +414,6 @@
}
@Override
- public void visitAttribute(Attribute attr) {
- // Unknown attribute must only be ignored
- }
-
- @Override
public void visitEnd() {
if (defaultAnnotations != null) {
addAnnotation(DexAnnotation.createAnnotationDefaultAnnotation(
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
index 6731b5e..3387ff2 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
@@ -46,7 +46,7 @@
*/
final Set<DexProgramClass> interfacesWithUnknownSubtypeHierarchy = Sets.newIdentityHashSet();
- /** Map of types directly implemented by lambdas to those lambdas. */
+ /** Map of types directly implemented by lambdas to those types. */
final Map<DexType, List<LambdaDescriptor>> instantiatedLambdas = new IdentityHashMap<>();
/**
@@ -215,6 +215,40 @@
return instantiatedLambdas.keySet();
}
+ public void removeAllocationsForPrunedItems(PrunedItems prunedItems) {
+ Set<DexType> removedClasses = prunedItems.getRemovedClasses();
+ if (removedClasses.isEmpty()) {
+ return;
+ }
+ classesWithAllocationSiteTracking
+ .entrySet()
+ .removeIf(entry -> removedClasses.contains(entry.getKey().getType()));
+ classesWithoutAllocationSiteTracking.removeIf(
+ clazz -> removedClasses.contains(clazz.getType()));
+ boolean removed =
+ interfacesWithUnknownSubtypeHierarchy.removeIf(
+ iface -> removedClasses.contains(iface.getType()));
+ assert !removed : "Unexpected removal of an interface marking an unknown hierarchy.";
+ removedClasses.forEach(instantiatedLambdas::remove);
+ }
+
+ public boolean verifyAllocatedTypesAreLive(
+ Set<DexType> liveTypes, DexDefinitionSupplier definitions) {
+ for (DexProgramClass clazz : classesWithAllocationSiteTracking.keySet()) {
+ assert liveTypes.contains(clazz.getType());
+ }
+ for (DexProgramClass clazz : classesWithoutAllocationSiteTracking) {
+ assert liveTypes.contains(clazz.getType());
+ }
+ for (DexProgramClass iface : interfacesWithUnknownSubtypeHierarchy) {
+ assert liveTypes.contains(iface.getType());
+ }
+ for (DexType iface : instantiatedLambdas.keySet()) {
+ assert definitions.definitionFor(iface).isNotProgramClass() || liveTypes.contains(iface);
+ }
+ return true;
+ }
+
public static class Builder extends ObjectAllocationInfoCollectionImpl {
private static class Data {
diff --git a/src/main/java/com/android/tools/r8/graph/PrunedItems.java b/src/main/java/com/android/tools/r8/graph/PrunedItems.java
new file mode 100644
index 0000000..2df596c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/PrunedItems.java
@@ -0,0 +1,92 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.graph;
+
+import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.Set;
+
+public class PrunedItems {
+
+ private final DexApplication prunedApp;
+ private final Set<DexReference> additionalPinnedItems;
+ private final Set<DexType> noLongerSyntheticItems;
+ private final Set<DexType> removedClasses;
+
+ private PrunedItems(
+ DexApplication prunedApp,
+ Set<DexReference> additionalPinnedItems,
+ Set<DexType> noLongerSyntheticItems,
+ Set<DexType> removedClasses) {
+ this.prunedApp = prunedApp;
+ this.additionalPinnedItems = additionalPinnedItems;
+ this.noLongerSyntheticItems = noLongerSyntheticItems;
+ this.removedClasses = removedClasses;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ public static PrunedItems empty(DexApplication application) {
+ return new Builder().setPrunedApp(application).build();
+ }
+
+ public DexApplication getPrunedApp() {
+ return prunedApp;
+ }
+
+ public Set<? extends DexReference> getAdditionalPinnedItems() {
+ return additionalPinnedItems;
+ }
+
+ public Set<DexType> getNoLongerSyntheticItems() {
+ return noLongerSyntheticItems;
+ }
+
+ public boolean hasRemovedClasses() {
+ return !removedClasses.isEmpty();
+ }
+
+ public Set<DexType> getRemovedClasses() {
+ return removedClasses;
+ }
+
+ public static class Builder {
+
+ private DexApplication prunedApp;
+
+ private final Set<DexReference> additionalPinnedItems = Sets.newIdentityHashSet();
+ private final Set<DexType> noLongerSyntheticItems = Sets.newIdentityHashSet();
+ private final Set<DexType> removedClasses = Sets.newIdentityHashSet();
+
+ public Builder setPrunedApp(DexApplication prunedApp) {
+ this.prunedApp = prunedApp;
+ return this;
+ }
+
+ public Builder addAdditionalPinnedItems(
+ Collection<? extends DexReference> additionalPinnedItems) {
+ this.additionalPinnedItems.addAll(additionalPinnedItems);
+ return this;
+ }
+
+ public Builder addNoLongerSyntheticItems(Set<DexType> noLongerSyntheticItems) {
+ this.noLongerSyntheticItems.addAll(noLongerSyntheticItems);
+ return this;
+ }
+
+ public Builder addRemovedClasses(Set<DexType> removedClasses) {
+ this.noLongerSyntheticItems.addAll(removedClasses);
+ this.removedClasses.addAll(removedClasses);
+ return this;
+ }
+
+ public PrunedItems build() {
+ return new PrunedItems(
+ prunedApp, additionalPinnedItems, noLongerSyntheticItems, removedClasses);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
index c8fc0a8..add54d6 100644
--- a/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
+++ b/src/main/java/com/android/tools/r8/graph/RewrittenPrototypeDescription.java
@@ -329,14 +329,16 @@
}
}
- private static final RewrittenPrototypeDescription none = new RewrittenPrototypeDescription();
+ private static final RewrittenPrototypeDescription NONE = new RewrittenPrototypeDescription();
private final List<ExtraParameter> extraParameters;
private final ArgumentInfoCollection argumentInfoCollection;
private final RewrittenTypeInfo rewrittenReturnInfo;
private RewrittenPrototypeDescription() {
- this(Collections.emptyList(), null, ArgumentInfoCollection.empty());
+ this.extraParameters = Collections.emptyList();
+ this.rewrittenReturnInfo = null;
+ this.argumentInfoCollection = ArgumentInfoCollection.empty();
}
private RewrittenPrototypeDescription(
@@ -347,6 +349,16 @@
this.extraParameters = extraParameters;
this.rewrittenReturnInfo = rewrittenReturnInfo;
this.argumentInfoCollection = argumentsInfo;
+ assert !isEmpty();
+ }
+
+ private static RewrittenPrototypeDescription create(
+ List<ExtraParameter> extraParameters,
+ RewrittenTypeInfo rewrittenReturnInfo,
+ ArgumentInfoCollection argumentsInfo) {
+ return extraParameters.isEmpty() && rewrittenReturnInfo == null && argumentsInfo.isEmpty()
+ ? none()
+ : new RewrittenPrototypeDescription(extraParameters, rewrittenReturnInfo, argumentsInfo);
}
public static RewrittenPrototypeDescription createForUninstantiatedTypes(
@@ -356,18 +368,16 @@
DexType returnType = method.proto.returnType;
RewrittenTypeInfo returnInfo =
returnType.isAlwaysNull(appView) ? RewrittenTypeInfo.toVoid(returnType, appView) : null;
- return new RewrittenPrototypeDescription(
- Collections.emptyList(), returnInfo, removedArgumentsInfo);
+ return create(Collections.emptyList(), returnInfo, removedArgumentsInfo);
}
public static RewrittenPrototypeDescription createForRewrittenTypes(
RewrittenTypeInfo returnInfo, ArgumentInfoCollection rewrittenArgumentsInfo) {
- return new RewrittenPrototypeDescription(
- Collections.emptyList(), returnInfo, rewrittenArgumentsInfo);
+ return create(Collections.emptyList(), returnInfo, rewrittenArgumentsInfo);
}
public static RewrittenPrototypeDescription none() {
- return none;
+ return NONE;
}
public boolean isEmpty() {
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java b/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java
index 0b5bc41..3a9f618 100644
--- a/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java
+++ b/src/main/java/com/android/tools/r8/graph/classmerging/HorizontallyMergedLambdaClasses.java
@@ -8,7 +8,9 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.optimize.lambda.LambdaGroup;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneMap;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
@@ -19,8 +21,10 @@
private final BidirectionalManyToOneMap<DexType, DexType> mergedClasses;
public HorizontallyMergedLambdaClasses(Map<DexType, LambdaGroup> lambdas) {
- this.mergedClasses = new BidirectionalManyToOneMap<>();
+ MutableBidirectionalManyToOneMap<DexType, DexType> mergedClasses =
+ new BidirectionalManyToOneHashMap<>();
lambdas.forEach((lambda, group) -> mergedClasses.put(lambda, group.getGroupClassType()));
+ this.mergedClasses = mergedClasses;
}
public static HorizontallyMergedLambdaClasses empty() {
@@ -29,7 +33,7 @@
@Override
public void forEachMergeGroup(BiConsumer<Set<DexType>, DexType> consumer) {
- mergedClasses.forEach(consumer);
+ mergedClasses.forEachManyToOneMapping(consumer);
}
@Override
@@ -38,6 +42,11 @@
}
@Override
+ public boolean isMergeTarget(DexType type) {
+ return mergedClasses.containsValue(type);
+ }
+
+ @Override
public boolean verifyAllSourcesPruned(AppView<AppInfoWithLiveness> appView) {
for (DexType source : mergedClasses.keySet()) {
assert appView.appInfo().wasPruned(source)
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/MergedClasses.java b/src/main/java/com/android/tools/r8/graph/classmerging/MergedClasses.java
index 25879f1..ae77e17 100644
--- a/src/main/java/com/android/tools/r8/graph/classmerging/MergedClasses.java
+++ b/src/main/java/com/android/tools/r8/graph/classmerging/MergedClasses.java
@@ -17,6 +17,8 @@
boolean hasBeenMergedIntoDifferentType(DexType type);
+ boolean isMergeTarget(DexType type);
+
boolean verifyAllSourcesPruned(AppView<AppInfoWithLiveness> appView);
/**
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/MergedClassesCollection.java b/src/main/java/com/android/tools/r8/graph/classmerging/MergedClassesCollection.java
index 5875506..33bee51 100644
--- a/src/main/java/com/android/tools/r8/graph/classmerging/MergedClassesCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/classmerging/MergedClassesCollection.java
@@ -38,6 +38,16 @@
}
@Override
+ public boolean isMergeTarget(DexType type) {
+ for (MergedClasses mergedClasses : collection) {
+ if (mergedClasses.isMergeTarget(type)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
public boolean verifyAllSourcesPruned(AppView<AppInfoWithLiveness> appView) {
for (MergedClasses mergedClasses : collection) {
assert mergedClasses.verifyAllSourcesPruned(appView);
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/StaticallyMergedClasses.java b/src/main/java/com/android/tools/r8/graph/classmerging/StaticallyMergedClasses.java
index 79e4ef7..9aabf18 100644
--- a/src/main/java/com/android/tools/r8/graph/classmerging/StaticallyMergedClasses.java
+++ b/src/main/java/com/android/tools/r8/graph/classmerging/StaticallyMergedClasses.java
@@ -8,7 +8,10 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneMap;
+import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneMap;
import java.util.Set;
import java.util.function.BiConsumer;
@@ -21,7 +24,7 @@
}
public static StaticallyMergedClasses empty() {
- return new StaticallyMergedClasses(BidirectionalManyToOneMap.empty());
+ return new StaticallyMergedClasses(new EmptyBidirectionalOneToOneMap<>());
}
public static Builder builder() {
@@ -30,7 +33,7 @@
@Override
public void forEachMergeGroup(BiConsumer<Set<DexType>, DexType> consumer) {
- mergedClasses.forEach(consumer);
+ mergedClasses.forEachManyToOneMapping(consumer);
}
@Override
@@ -39,14 +42,21 @@
}
@Override
+ public boolean isMergeTarget(DexType type) {
+ // Intentionally returns false since static class merging technically doesn't merge any classes,
+ // it only moves static members.
+ return false;
+ }
+
+ @Override
public boolean verifyAllSourcesPruned(AppView<AppInfoWithLiveness> appView) {
return true;
}
public static class Builder {
- private final BidirectionalManyToOneMap<DexType, DexType> mergedClasses =
- new BidirectionalManyToOneMap<>();
+ private final MutableBidirectionalManyToOneMap<DexType, DexType> mergedClasses =
+ new BidirectionalManyToOneHashMap<>();
private Builder() {}
diff --git a/src/main/java/com/android/tools/r8/graph/classmerging/VerticallyMergedClasses.java b/src/main/java/com/android/tools/r8/graph/classmerging/VerticallyMergedClasses.java
index 6ba32e9..3b59401 100644
--- a/src/main/java/com/android/tools/r8/graph/classmerging/VerticallyMergedClasses.java
+++ b/src/main/java/com/android/tools/r8/graph/classmerging/VerticallyMergedClasses.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneMap;
+import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
@@ -22,12 +23,12 @@
}
public static VerticallyMergedClasses empty() {
- return new VerticallyMergedClasses(BidirectionalManyToOneMap.empty());
+ return new VerticallyMergedClasses(new EmptyBidirectionalOneToOneMap<>());
}
@Override
public void forEachMergeGroup(BiConsumer<Set<DexType>, DexType> consumer) {
- mergedClasses.forEach(consumer);
+ mergedClasses.forEachManyToOneMapping(consumer);
}
public Map<DexType, DexType> getForwardMap() {
@@ -55,7 +56,8 @@
return mergedClasses.isEmpty();
}
- public boolean isTarget(DexType type) {
+ @Override
+ public boolean isMergeTarget(DexType type) {
return !getSourcesFor(type).isEmpty();
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInitializerSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInitializerSynthesizedCode.java
new file mode 100644
index 0000000..c919e63
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInitializerSynthesizedCode.java
@@ -0,0 +1,100 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.horizontalclassmerging;
+
+import static com.android.tools.r8.utils.ConsumerUtils.apply;
+import static java.lang.Integer.max;
+
+import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.cf.code.CfGoto;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.cf.code.CfLabel;
+import com.android.tools.r8.cf.code.CfReturnVoid;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.CfVersionUtils;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+public class ClassInitializerSynthesizedCode {
+ private final List<DexEncodedMethod> staticClassInitializers;
+ private int maxStack = 0;
+ private int maxLocals = 0;
+
+ private ClassInitializerSynthesizedCode(List<DexEncodedMethod> staticClassInitializers) {
+ this.staticClassInitializers = staticClassInitializers;
+ }
+
+ public boolean isEmpty() {
+ return staticClassInitializers.isEmpty();
+ }
+
+ private void addCfCode(List<CfInstruction> newInstructions, DexEncodedMethod method) {
+ CfCode code = method.getCode().asCfCode();
+ maxStack = max(maxStack, code.getMaxStack());
+ maxLocals = max(maxLocals, code.getMaxLocals());
+
+ CfLabel endLabel = new CfLabel();
+ boolean requiresLabel = false;
+ int index = 1;
+ for (CfInstruction instruction : code.getInstructions()) {
+ if (instruction.isReturn()) {
+ if (code.getInstructions().size() != index) {
+ newInstructions.add(new CfGoto(endLabel));
+ requiresLabel = true;
+ }
+ } else {
+ newInstructions.add(instruction);
+ }
+
+ index++;
+ }
+ if (requiresLabel) {
+ newInstructions.add(endLabel);
+ }
+ }
+
+ public CfCode synthesizeCode(DexType originalHolder) {
+ return new CfCode(
+ originalHolder,
+ maxStack,
+ maxLocals,
+ buildInstructions(),
+ Collections.emptyList(),
+ Collections.emptyList());
+ }
+
+ private List<CfInstruction> buildInstructions() {
+ List<CfInstruction> newInstructions = new ArrayList<>();
+ staticClassInitializers.forEach(apply(this::addCfCode, newInstructions));
+ newInstructions.add(new CfReturnVoid());
+ return newInstructions;
+ }
+
+ public DexEncodedMethod getFirst() {
+ return staticClassInitializers.iterator().next();
+ }
+
+ public CfVersion getCfVersion() {
+ return CfVersionUtils.max(staticClassInitializers);
+ }
+
+ public static class Builder {
+ private final List<DexEncodedMethod> staticClassInitializers = new ArrayList<>();
+
+ public void add(DexEncodedMethod method) {
+ assert method.isClassInitializer();
+ assert method.hasCode();
+ assert method.getCode().isCfCode();
+ staticClassInitializers.add(method);
+ }
+
+ public ClassInitializerSynthesizedCode build() {
+ return new ClassInitializerSynthesizedCode(staticClassInitializers);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java
index 26ed21c..96282ee 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassInstanceFieldsMerger.java
@@ -5,11 +5,12 @@
package com.android.tools.r8.horizontalclassmerging;
import com.android.tools.r8.graph.DexEncodedField;
-import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.horizontalclassmerging.HorizontalClassMergerGraphLens.Builder;
+import com.android.tools.r8.utils.IterableUtils;
import com.android.tools.r8.utils.ListUtils;
+import com.google.common.collect.Iterables;
import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
@@ -50,20 +51,19 @@
}
}
- private void mergeField(DexEncodedField oldField, DexEncodedField newField) {
- if (newField.isFinal() && !oldField.isFinal()) {
+ private void fixAccessFlags(DexEncodedField newField, Collection<DexEncodedField> oldFields) {
+ if (newField.isFinal() && Iterables.any(oldFields, oldField -> !oldField.isFinal())) {
newField.getAccessFlags().demoteFromFinal();
}
- lensBuilder.moveField(oldField.field, newField.field);
}
- private void mergeFields(DexEncodedField newField, Collection<DexEncodedField> oldFields) {
- DexField newFieldReference = newField.getReference();
-
- lensBuilder.moveField(newFieldReference, newFieldReference);
- lensBuilder.setRepresentativeField(newFieldReference, newFieldReference);
-
- oldFields.forEach(oldField -> mergeField(oldField, newField));
+ private void mergeFields(DexEncodedField newField, List<DexEncodedField> oldFields) {
+ fixAccessFlags(newField, oldFields);
+ lensBuilder.recordNewFieldSignature(
+ Iterables.transform(
+ IterableUtils.append(oldFields, newField), DexEncodedField::getReference),
+ newField.getReference(),
+ newField.getReference());
}
public void merge() {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index 04b4b68..950cf9a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -6,8 +6,10 @@
import static com.google.common.base.Predicates.not;
+import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -19,6 +21,9 @@
import com.android.tools.r8.graph.DexTypeList;
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
+import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
+import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
@@ -46,8 +51,10 @@
public static final String CLASS_ID_FIELD_NAME = "$r8$classId";
+ private final AppView<AppInfoWithLiveness> appView;
private final MergeGroup group;
private final DexItemFactory dexItemFactory;
+ private final ClassInitializerSynthesizedCode classInitializerSynthesizedCode;
private final HorizontalClassMergerGraphLens.Builder lensBuilder;
private final HorizontallyMergedClasses.Builder mergedClassesBuilder;
private final FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder;
@@ -66,7 +73,9 @@
FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder,
MergeGroup group,
Collection<VirtualMethodMerger> virtualMethodMergers,
- Collection<ConstructorMerger> constructorMergers) {
+ Collection<ConstructorMerger> constructorMergers,
+ ClassInitializerSynthesizedCode classInitializerSynthesizedCode) {
+ this.appView = appView;
this.lensBuilder = lensBuilder;
this.mergedClassesBuilder = mergedClassesBuilder;
this.fieldAccessChangesBuilder = fieldAccessChangesBuilder;
@@ -75,6 +84,7 @@
this.constructorMergers = constructorMergers;
this.dexItemFactory = appView.dexItemFactory();
+ this.classInitializerSynthesizedCode = classInitializerSynthesizedCode;
this.classStaticFieldsMerger = new ClassStaticFieldsMerger(appView, lensBuilder, group);
this.classInstanceFieldsMerger = new ClassInstanceFieldsMerger(lensBuilder, group);
@@ -91,18 +101,54 @@
}
void mergeDirectMethods(SyntheticArgumentClass syntheticArgumentClass) {
+ mergeStaticClassInitializers();
mergeDirectMethods(group.getTarget());
group.forEachSource(this::mergeDirectMethods);
mergeConstructors(syntheticArgumentClass);
}
+ void mergeStaticClassInitializers() {
+ if (classInitializerSynthesizedCode.isEmpty()) {
+ return;
+ }
+
+ DexMethod newClinit = dexItemFactory.createClassInitializer(group.getTarget().getType());
+
+ CfCode code = classInitializerSynthesizedCode.synthesizeCode(group.getTarget().getType());
+ if (!group.getTarget().hasClassInitializer()) {
+ classMethodsBuilder.addDirectMethod(
+ new DexEncodedMethod(
+ newClinit,
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_SYNTHETIC | Constants.ACC_STATIC, true),
+ MethodTypeSignature.noSignature(),
+ DexAnnotationSet.empty(),
+ ParameterAnnotationsList.empty(),
+ code,
+ true,
+ classInitializerSynthesizedCode.getCfVersion()));
+ } else {
+ DexEncodedMethod clinit = group.getTarget().getClassInitializer();
+ clinit.setCode(code, appView);
+ CfVersion cfVersion = classInitializerSynthesizedCode.getCfVersion();
+ if (cfVersion != null) {
+ clinit.upgradeClassFileVersion(cfVersion);
+ } else {
+ assert appView.options().isGeneratingDex();
+ }
+ classMethodsBuilder.addDirectMethod(clinit);
+ }
+ }
+
void mergeDirectMethods(DexProgramClass toMerge) {
toMerge.forEachProgramDirectMethod(
method -> {
DexEncodedMethod definition = method.getDefinition();
- assert !definition.isClassInitializer();
-
- if (!definition.isInstanceInitializer()) {
+ if (definition.isClassInitializer()) {
+ lensBuilder.moveMethod(
+ method.getReference(),
+ dexItemFactory.createClassInitializer(group.getTarget().getType()));
+ } else if (!definition.isInstanceInitializer()) {
DexMethod newMethod =
method.getReference().withHolder(group.getTarget().getType(), dexItemFactory);
if (!classMethodsBuilder.isFresh(newMethod)) {
@@ -114,7 +160,6 @@
}
}
});
-
// Clear the members of the class to be merged since they have now been moved to the target.
toMerge.getMethodCollection().clearDirectMethods();
}
@@ -217,6 +262,8 @@
public static class Builder {
private final AppView<AppInfoWithLiveness> appView;
private final MergeGroup group;
+ private final ClassInitializerSynthesizedCode.Builder classInitializerSynthesizedCodeBuilder =
+ new ClassInitializerSynthesizedCode.Builder();
private final Map<DexProto, ConstructorMerger.Builder> constructorMergerBuilders =
new LinkedHashMap<>();
private final List<ConstructorMerger.Builder> unmergedConstructorBuilders = new ArrayList<>();
@@ -242,20 +289,17 @@
}
private void setupForMethodMerging(DexProgramClass toMerge) {
- toMerge.forEachProgramDirectMethod(
- method -> {
- DexEncodedMethod definition = method.getDefinition();
- assert !definition.isClassInitializer();
- if (definition.isInstanceInitializer()) {
- addConstructor(method);
- }
- });
+ if (toMerge.hasClassInitializer()) {
+ classInitializerSynthesizedCodeBuilder.add(toMerge.getClassInitializer());
+ }
+ toMerge.forEachProgramDirectMethodMatching(
+ DexEncodedMethod::isInstanceInitializer, this::addConstructor);
toMerge.forEachProgramVirtualMethod(this::addVirtualMethod);
}
private void addConstructor(ProgramMethod method) {
assert method.getDefinition().isInstanceInitializer();
- if (appView.options().enableHorizontalClassMergingConstructorMerging) {
+ if (appView.options().horizontalClassMergerOptions().isConstructorMergingEnabled()) {
constructorMergerBuilders
.computeIfAbsent(
method.getDefinition().getProto(), ignore -> new ConstructorMerger.Builder(appView))
@@ -276,7 +320,7 @@
}
private Collection<ConstructorMerger.Builder> getConstructorMergerBuilders() {
- return appView.options().enableHorizontalClassMergingConstructorMerging
+ return appView.options().horizontalClassMergerOptions().isConstructorMergingEnabled()
? constructorMergerBuilders.values()
: unmergedConstructorBuilders;
}
@@ -313,7 +357,8 @@
fieldAccessChangesBuilder,
group,
virtualMethodMergers,
- constructorMergers);
+ constructorMergers,
+ classInitializerSynthesizedCodeBuilder.build());
}
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassStaticFieldsMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassStaticFieldsMerger.java
index 7bc85d1..80180f6 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassStaticFieldsMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassStaticFieldsMerger.java
@@ -33,7 +33,7 @@
this.dexItemFactory = appView.dexItemFactory();
}
- private final boolean isFresh(DexField fieldReference) {
+ private boolean isFresh(DexField fieldReference) {
return !targetFields.containsKey(fieldReference);
}
@@ -48,7 +48,7 @@
field = field.toTypeSubstitutedField(newFieldReference);
targetFields.put(newFieldReference, field);
- lensBuilder.moveField(oldFieldReference, newFieldReference);
+ lensBuilder.recordNewFieldSignature(oldFieldReference, newFieldReference);
}
public void addFields(DexProgramClass toMerge) {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
index d2cd444..01d5771 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.horizontalclassmerging;
+import static com.android.tools.r8.dex.Constants.TEMPORARY_INSTANCE_INITIALIZER_PREFIX;
+
import com.android.tools.r8.cf.CfVersion;
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppView;
@@ -28,7 +30,6 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
-import java.util.LinkedList;
import java.util.List;
public class ConstructorMerger {
@@ -111,7 +112,7 @@
ClassMethodsBuilder classMethodsBuilder, DexEncodedMethod constructor) {
DexMethod method =
dexItemFactory.createFreshMethodName(
- "constructor",
+ TEMPORARY_INSTANCE_INITIALIZER_PREFIX,
constructor.getHolderType(),
constructor.proto(),
group.getTarget().getType(),
@@ -152,7 +153,7 @@
}
DexMethod movedConstructor = moveConstructor(classMethodsBuilder, constructor);
lensBuilder.mapMethod(movedConstructor, movedConstructor);
- lensBuilder.mapMethodInverse(constructor.method, movedConstructor);
+ lensBuilder.recordNewMethodSignature(constructor.getReference(), movedConstructor);
typeConstructorClassMap.put(
classIdentifiers.getInt(constructor.getHolderType()), movedConstructor);
}
@@ -165,13 +166,29 @@
classMethodsBuilder::isFresh);
int extraNulls = newConstructorReference.getArity() - methodReferenceTemplate.getArity();
- DexMethod representativeConstructorReference = constructors.iterator().next().method;
+ DexEncodedMethod representative = constructors.iterator().next();
+ DexMethod originalConstructorReference =
+ appView.graphLens().getOriginalMethodSignature(representative.getReference());
+
+ // Create a special original method signature for the synthesized constructor that did not exist
+ // prior to horizontal class merging. Otherwise we might accidentally think that the synthesized
+ // constructor corresponds to the previous <init>() method on the target class, which could have
+ // unintended side-effects such as leading to unused argument removal being applied to the
+ // synthesized constructor all-though it by construction doesn't have any unused arguments.
+ DexMethod bridgeConstructorReference =
+ dexItemFactory.createFreshMethodName(
+ "$r8$init$bridge",
+ null,
+ originalConstructorReference.getProto(),
+ originalConstructorReference.getHolderType(),
+ classMethodsBuilder::isFresh);
+
ConstructorEntryPointSynthesizedCode synthesizedCode =
new ConstructorEntryPointSynthesizedCode(
typeConstructorClassMap,
newConstructorReference,
group.getClassIdField(),
- appView.graphLens().getOriginalMethodSignature(representativeConstructorReference));
+ bridgeConstructorReference);
DexEncodedMethod newConstructor =
new DexEncodedMethod(
newConstructorReference,
@@ -183,34 +200,20 @@
true,
classFileVersion);
- if (isTrivialMerge()) {
- // The constructor does not require the additional argument, just map it like a regular
- // method.
- DexEncodedMethod oldConstructor = constructors.iterator().next();
- if (extraNulls > 0) {
- List<ExtraParameter> extraParameters = new LinkedList<>();
- extraParameters.addAll(Collections.nCopies(extraNulls, new ExtraUnusedNullParameter()));
- lensBuilder.moveMergedConstructor(
- oldConstructor.method, newConstructorReference, extraParameters);
- } else {
- lensBuilder.moveMethod(oldConstructor.method, newConstructorReference);
- }
- } else {
- // Map each old constructor to the newly synthesized constructor in the graph lens.
- for (DexEncodedMethod oldConstructor : constructors) {
+ // Map each old constructor to the newly synthesized constructor in the graph lens.
+ for (DexEncodedMethod oldConstructor : constructors) {
+ List<ExtraParameter> extraParameters = new ArrayList<>();
+ if (constructors.size() > 1) {
int classIdentifier = classIdentifiers.getInt(oldConstructor.getHolderType());
-
- List<ExtraParameter> extraParameters = new LinkedList<>();
extraParameters.add(new ExtraConstantIntParameter(classIdentifier));
- extraParameters.addAll(Collections.nCopies(extraNulls, new ExtraUnusedNullParameter()));
-
- lensBuilder.moveMergedConstructor(
- oldConstructor.method, newConstructorReference, extraParameters);
}
+ extraParameters.addAll(Collections.nCopies(extraNulls, new ExtraUnusedNullParameter()));
+ lensBuilder.mapMergedConstructor(
+ oldConstructor.getReference(), newConstructorReference, extraParameters);
}
- // Map the first constructor to the newly synthesized constructor.
- lensBuilder.recordExtraOriginalSignature(
- representativeConstructorReference, newConstructorReference);
+
+ // Add a mapping from a synthetic name to the synthetic constructor.
+ lensBuilder.recordNewMethodSignature(bridgeConstructorReference, newConstructorReference);
classMethodsBuilder.addDirectMethod(newConstructor);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index 0821a4c..5983618 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.horizontalclassmerging.policies.IgnoreSynthetics;
import com.android.tools.r8.horizontalclassmerging.policies.LimitGroups;
import com.android.tools.r8.horizontalclassmerging.policies.NoAnnotations;
+import com.android.tools.r8.horizontalclassmerging.policies.NoClassInitializerWithObservableSideEffects;
import com.android.tools.r8.horizontalclassmerging.policies.NoClassesOrMembersWithAnnotations;
import com.android.tools.r8.horizontalclassmerging.policies.NoDirectRuntimeTypeChecks;
import com.android.tools.r8.horizontalclassmerging.policies.NoEnums;
@@ -26,7 +27,6 @@
import com.android.tools.r8.horizontalclassmerging.policies.NoKotlinMetadata;
import com.android.tools.r8.horizontalclassmerging.policies.NoNativeMethods;
import com.android.tools.r8.horizontalclassmerging.policies.NoServiceLoaders;
-import com.android.tools.r8.horizontalclassmerging.policies.NoStaticClassInitializer;
import com.android.tools.r8.horizontalclassmerging.policies.NotMatchedByNoHorizontalClassMerging;
import com.android.tools.r8.horizontalclassmerging.policies.NotVerticallyMergedIntoSubtype;
import com.android.tools.r8.horizontalclassmerging.policies.PreserveMethodCharacteristics;
@@ -64,11 +64,9 @@
MergeGroup initialGroup = new MergeGroup(appView.appInfo().classesWithDeterministicOrder());
// Run the policies on all program classes to produce a final grouping.
+ List<Policy> policies = getPolicies(mainDexTracingResult, runtimeTypeCheckInfo);
Collection<MergeGroup> groups =
- new SimplePolicyExecutor()
- .run(
- Collections.singletonList(initialGroup),
- getPolicies(mainDexTracingResult, runtimeTypeCheckInfo));
+ new SimplePolicyExecutor().run(Collections.singletonList(initialGroup), policies);
// If there are no groups, then end horizontal class merging.
if (groups.isEmpty()) {
@@ -116,7 +114,7 @@
new IgnoreSynthetics(appView),
new NoClassesOrMembersWithAnnotations(),
new NoInnerClasses(),
- new NoStaticClassInitializer(),
+ new NoClassInitializerWithObservableSideEffects(),
new NoNativeMethods(),
new NoKeepRules(appView),
new NoKotlinMetadata(),
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
index 16f853e..3adad2e 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
@@ -8,89 +8,51 @@
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.GraphLens;
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.conversion.ExtraParameter;
import com.android.tools.r8.utils.IterableUtils;
-import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
-import com.google.common.collect.BiMap;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeHashMap;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToManyRepresentativeHashMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToManyRepresentativeMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneRepresentativeMap;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Streams;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
-import java.util.function.Function;
public class HorizontalClassMergerGraphLens extends NestedGraphLens {
private final Map<DexMethod, List<ExtraParameter>> methodExtraParameters;
- private final Map<DexMethod, DexMethod> extraOriginalMethodSignatures;
private final HorizontallyMergedClasses mergedClasses;
- private final Map<DexField, DexField> extraOriginalFieldSignatures;
private HorizontalClassMergerGraphLens(
AppView<?> appView,
HorizontallyMergedClasses mergedClasses,
Map<DexMethod, List<ExtraParameter>> methodExtraParameters,
- Map<DexField, DexField> fieldMap,
+ BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap,
Map<DexMethod, DexMethod> methodMap,
- BiMap<DexField, DexField> originalFieldSignatures,
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> originalMethodSignatures,
- Map<DexMethod, DexMethod> extraOriginalMethodSignatures,
- Map<DexField, DexField> extraOriginalFieldSignatures,
- GraphLens previousLens) {
+ BidirectionalOneToManyRepresentativeMap<DexMethod, DexMethod> originalMethodSignatures) {
super(
mergedClasses.getForwardMap(),
methodMap,
fieldMap,
- originalFieldSignatures,
originalMethodSignatures,
- previousLens,
+ appView.graphLens(),
appView.dexItemFactory());
this.methodExtraParameters = methodExtraParameters;
- this.extraOriginalFieldSignatures = extraOriginalFieldSignatures;
- this.extraOriginalMethodSignatures = extraOriginalMethodSignatures;
this.mergedClasses = mergedClasses;
}
- private boolean isSynthesizedByHorizontalClassMerging(DexMethod method) {
- return methodExtraParameters.containsKey(method);
- }
-
@Override
protected Iterable<DexType> internalGetOriginalTypes(DexType previous) {
return IterableUtils.prependSingleton(previous, mergedClasses.getSourcesFor(previous));
}
- @Override
- public RewrittenPrototypeDescription lookupPrototypeChangesForMethodDefinition(DexMethod method) {
- if (isSynthesizedByHorizontalClassMerging(method)) {
- // If we are processing the call site, the arguments should be removed.
- return RewrittenPrototypeDescription.none();
- }
- return super.lookupPrototypeChangesForMethodDefinition(method);
- }
-
- @Override
- public DexMethod getOriginalMethodSignature(DexMethod method) {
- DexMethod originalConstructor = extraOriginalMethodSignatures.get(method);
- if (originalConstructor == null) {
- return super.getOriginalMethodSignature(method);
- }
- return getPrevious().getOriginalMethodSignature(originalConstructor);
- }
-
- @Override
- public DexField getOriginalFieldSignature(DexField field) {
- DexField originalField = extraOriginalFieldSignatures.get(field);
- if (originalField == null) {
- return super.getOriginalFieldSignature(field);
- }
- return getPrevious().getOriginalFieldSignature(originalField);
- }
-
/**
* If an overloaded constructor is requested, add the constructor id as a parameter to the
* constructor. Otherwise return the lookup on the underlying graph lens.
@@ -111,87 +73,121 @@
}
public static class Builder {
- private ManyToOneMap<DexField, DexField> fieldMap = new ManyToOneMap<>();
- private ManyToOneMap<DexMethod, DexMethod> methodMap = new ManyToOneMap<>();
+
+ private final MutableBidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap =
+ new BidirectionalManyToOneRepresentativeHashMap<>();
+ private final BidirectionalManyToOneHashMap<DexMethod, DexMethod> methodMap =
+ new BidirectionalManyToOneHashMap<>();
+ private final BidirectionalOneToManyRepresentativeHashMap<DexMethod, DexMethod>
+ originalMethodSignatures = new BidirectionalOneToManyRepresentativeHashMap<>();
private final Map<DexMethod, List<ExtraParameter>> methodExtraParameters =
new IdentityHashMap<>();
+ private final BidirectionalManyToOneHashMap<DexMethod, DexMethod> pendingMethodMapUpdates =
+ new BidirectionalManyToOneHashMap<>();
+ private final BidirectionalOneToManyRepresentativeHashMap<DexMethod, DexMethod>
+ pendingOriginalMethodSignatureUpdates = new BidirectionalOneToManyRepresentativeHashMap<>();
+
Builder() {}
- public HorizontalClassMergerGraphLens build(
+ HorizontalClassMergerGraphLens build(
AppView<?> appView, HorizontallyMergedClasses mergedClasses) {
- ManyToOneInverseMap<DexMethod, DexMethod> inverseMethodMap =
- methodMap.inverse(
- group -> {
- // Every group should have a representative. Fail in debug mode.
- assert false;
- return group.iterator().next();
- });
- ManyToOneInverseMap<DexField, DexField> inverseFieldMap =
- fieldMap.inverse(
- group -> {
- // Every group should have a representative. Fail in debug mode.
- assert false;
- return group.iterator().next();
- });
-
+ assert pendingMethodMapUpdates.isEmpty();
+ assert pendingOriginalMethodSignatureUpdates.isEmpty();
return new HorizontalClassMergerGraphLens(
appView,
mergedClasses,
methodExtraParameters,
- fieldMap.getForwardMap(),
+ fieldMap,
methodMap.getForwardMap(),
- inverseFieldMap.getBiMap().getForwardBacking(),
- inverseMethodMap.getBiMap(),
- inverseMethodMap.getExtraMap(),
- inverseFieldMap.getExtraMap(),
- appView.graphLens());
+ originalMethodSignatures);
}
- public void remapMethods(BiMap<DexMethod, DexMethod> remapMethods) {
- methodMap = methodMap.remap(remapMethods, Function.identity(), Function.identity());
+ void recordNewFieldSignature(DexField oldFieldSignature, DexField newFieldSignature) {
+ fieldMap.put(oldFieldSignature, newFieldSignature);
}
- public void remapFields(BiMap<DexField, DexField> remapFields) {
- fieldMap = fieldMap.remap(remapFields, Function.identity(), Function.identity());
+ void recordNewFieldSignature(
+ Iterable<DexField> oldFieldSignatures,
+ DexField newFieldSignature,
+ DexField representative) {
+ assert Streams.stream(oldFieldSignatures)
+ .anyMatch(oldFieldSignature -> oldFieldSignature != newFieldSignature);
+ assert Streams.stream(oldFieldSignatures).noneMatch(fieldMap::containsValue);
+ assert Iterables.contains(oldFieldSignatures, representative);
+ for (DexField oldFieldSignature : oldFieldSignatures) {
+ recordNewFieldSignature(oldFieldSignature, newFieldSignature);
+ }
+ fieldMap.setRepresentative(newFieldSignature, representative);
}
- public Builder moveField(DexField from, DexField to) {
- fieldMap.put(from, to);
- fieldMap.putInverse(from, to);
- return this;
+ void fixupField(DexField oldFieldSignature, DexField newFieldSignature) {
+ Set<DexField> originalFieldSignatures = fieldMap.removeValue(oldFieldSignature);
+ if (originalFieldSignatures.isEmpty()) {
+ fieldMap.put(oldFieldSignature, newFieldSignature);
+ } else if (originalFieldSignatures.size() == 1) {
+ fieldMap.put(originalFieldSignatures.iterator().next(), newFieldSignature);
+ } else {
+ for (DexField originalFieldSignature : originalFieldSignatures) {
+ fieldMap.put(originalFieldSignature, newFieldSignature);
+ }
+ DexField representative = fieldMap.removeRepresentativeFor(oldFieldSignature);
+ assert representative != null;
+ fieldMap.setRepresentative(newFieldSignature, representative);
+ }
}
- public Builder setRepresentativeField(DexField from, DexField to) {
- fieldMap.setRepresentative(from, to);
- return this;
+ void mapMethod(DexMethod oldMethodSignature, DexMethod newMethodSignature) {
+ methodMap.put(oldMethodSignature, newMethodSignature);
}
- /** Unidirectional mapping from one method to another. */
- public Builder recordExtraOriginalSignature(DexMethod from, DexMethod to) {
- methodMap.setRepresentative(from, to);
-
- return this;
- }
-
- /** Unidirectional mapping from one method to another. */
- public Builder mapMethod(DexMethod from, DexMethod to) {
- methodMap.put(from, to);
-
- return this;
- }
-
- /** Unidirectional mapping from one method to another. */
- public Builder mapMethodInverse(DexMethod from, DexMethod to) {
- methodMap.putInverse(from, to);
-
- return this;
- }
-
- public Builder moveMethod(DexMethod from, DexMethod to) {
+ void moveMethod(DexMethod from, DexMethod to) {
mapMethod(from, to);
- mapMethodInverse(from, to);
- return this;
+ recordNewMethodSignature(from, to);
+ }
+
+ void recordNewMethodSignature(DexMethod oldMethodSignature, DexMethod newMethodSignature) {
+ originalMethodSignatures.put(newMethodSignature, oldMethodSignature);
+ }
+
+ void fixupMethod(DexMethod oldMethodSignature, DexMethod newMethodSignature) {
+ fixupMethodMap(oldMethodSignature, newMethodSignature);
+ fixupOriginalMethodSignatures(oldMethodSignature, newMethodSignature);
+ }
+
+ private void fixupMethodMap(DexMethod oldMethodSignature, DexMethod newMethodSignature) {
+ Set<DexMethod> originalMethodSignatures = methodMap.getKeys(oldMethodSignature);
+ if (originalMethodSignatures.isEmpty()) {
+ pendingMethodMapUpdates.put(oldMethodSignature, newMethodSignature);
+ } else {
+ for (DexMethod originalMethodSignature : originalMethodSignatures) {
+ pendingMethodMapUpdates.put(originalMethodSignature, newMethodSignature);
+ }
+ }
+ }
+
+ private void fixupOriginalMethodSignatures(
+ DexMethod oldMethodSignature, DexMethod newMethodSignature) {
+ Set<DexMethod> oldMethodSignatures = originalMethodSignatures.getValues(oldMethodSignature);
+ if (oldMethodSignatures.isEmpty()) {
+ pendingOriginalMethodSignatureUpdates.put(newMethodSignature, oldMethodSignature);
+ } else {
+ for (DexMethod originalMethodSignature : oldMethodSignatures) {
+ pendingOriginalMethodSignatureUpdates.put(newMethodSignature, originalMethodSignature);
+ }
+ }
+ }
+
+ void commitPendingUpdates() {
+ // Commit pending method map updates.
+ methodMap.removeAll(pendingMethodMapUpdates.keySet());
+ pendingMethodMapUpdates.forEachManyToOneMapping(methodMap::put);
+ pendingMethodMapUpdates.clear();
+
+ // Commit pending original method signatures updates.
+ originalMethodSignatures.removeAll(pendingOriginalMethodSignatureUpdates.keySet());
+ pendingOriginalMethodSignatureUpdates.forEachOneToManyMapping(originalMethodSignatures::put);
+ pendingOriginalMethodSignatureUpdates.clear();
}
/**
@@ -199,24 +195,27 @@
* where many constructors are merged into a single constructor. The synthesized constructor
* therefore does not have a unique reverse constructor.
*/
- public Builder moveMergedConstructor(
- DexMethod from, DexMethod to, List<ExtraParameter> extraParameters) {
- moveMethod(from, to);
- methodExtraParameters.put(from, extraParameters);
- return this;
+ void mapMergedConstructor(DexMethod from, DexMethod to, List<ExtraParameter> extraParameters) {
+ mapMethod(from, to);
+ if (extraParameters.size() > 0) {
+ methodExtraParameters.put(from, extraParameters);
+ }
}
- public Builder addExtraParameters(DexMethod to, List<ExtraParameter> extraParameters) {
- Set<DexMethod> mapsFrom = methodMap.lookupReverse(to);
- if (mapsFrom == null) {
- mapsFrom = Collections.singleton(to);
+ void addExtraParameters(DexMethod methodSignature, List<ExtraParameter> extraParameters) {
+ Set<DexMethod> originalMethodSignatures = methodMap.getKeys(methodSignature);
+ if (originalMethodSignatures.isEmpty()) {
+ methodExtraParameters
+ .computeIfAbsent(methodSignature, ignore -> new ArrayList<>(extraParameters.size()))
+ .addAll(extraParameters);
+ } else {
+ for (DexMethod originalMethodSignature : originalMethodSignatures) {
+ methodExtraParameters
+ .computeIfAbsent(
+ originalMethodSignature, ignore -> new ArrayList<>(extraParameters.size()))
+ .addAll(extraParameters);
+ }
}
- mapsFrom.forEach(
- originalFrom ->
- methodExtraParameters
- .computeIfAbsent(originalFrom, ignore -> new ArrayList<>(extraParameters.size()))
- .addAll(extraParameters));
- return this;
}
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontallyMergedClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontallyMergedClasses.java
index 4d6d93f..93f9d3f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontallyMergedClasses.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontallyMergedClasses.java
@@ -8,7 +8,10 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.classmerging.MergedClasses;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
import com.android.tools.r8.utils.collections.BidirectionalManyToOneMap;
+import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneMap;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
@@ -22,12 +25,12 @@
}
public static HorizontallyMergedClasses empty() {
- return new HorizontallyMergedClasses(new BidirectionalManyToOneMap<>());
+ return new HorizontallyMergedClasses(new EmptyBidirectionalOneToOneMap<>());
}
@Override
public void forEachMergeGroup(BiConsumer<Set<DexType>, DexType> consumer) {
- mergedClasses.forEach(consumer);
+ mergedClasses.forEachManyToOneMapping(consumer);
}
public DexType getMergeTargetOrDefault(DexType type) {
@@ -42,13 +45,18 @@
return mergedClasses.getKeys(type);
}
- @Override
- public boolean hasBeenMergedIntoDifferentType(DexType type) {
- return mergedClasses.hasKey(type);
+ public Set<DexType> getTargets() {
+ return mergedClasses.values();
}
+ @Override
+ public boolean hasBeenMergedIntoDifferentType(DexType type) {
+ return mergedClasses.containsKey(type);
+ }
+
+ @Override
public boolean isMergeTarget(DexType type) {
- return mergedClasses.hasValue(type);
+ return mergedClasses.containsValue(type);
}
public boolean hasBeenMergedOrIsMergeTarget(DexType type) {
@@ -71,8 +79,8 @@
}
public static class Builder {
- private final BidirectionalManyToOneMap<DexType, DexType> mergedClasses =
- new BidirectionalManyToOneMap<>();
+ private final MutableBidirectionalManyToOneMap<DexType, DexType> mergedClasses =
+ new BidirectionalManyToOneHashMap<>();
public HorizontallyMergedClasses build() {
return new HorizontallyMergedClasses(mergedClasses);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ManyToOneInverseMap.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ManyToOneInverseMap.java
deleted file mode 100644
index 973162f..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ManyToOneInverseMap.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.horizontalclassmerging;
-
-import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
-import java.util.Map;
-
-/** The inverse of a {@link ManyToOneMap} used for generating graph lens maps. */
-public class ManyToOneInverseMap<K, V> {
- private final BidirectionalOneToOneHashMap<V, K> biMap;
- private final Map<V, K> extraMap;
-
- ManyToOneInverseMap(BidirectionalOneToOneHashMap<V, K> biMap, Map<V, K> extraMap) {
- this.biMap = biMap;
- this.extraMap = extraMap;
- }
-
- public BidirectionalOneToOneHashMap<V, K> getBiMap() {
- return biMap;
- }
-
- public Map<V, K> getExtraMap() {
- return extraMap;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ManyToOneMap.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ManyToOneMap.java
deleted file mode 100644
index 5204021..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ManyToOneMap.java
+++ /dev/null
@@ -1,121 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.horizontalclassmerging;
-
-import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.IdentityHashMap;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-import java.util.function.Function;
-
-/**
- * This mapping class is used to track method mappings for horizontal class merging. Essentially it
- * is a bidirectional many to one map, but with support for having unidirectional mappings and with
- * support for remapping the values to new values using {@link ManyToOneMap#remap(BiMap, Function,
- * Function)}. It also supports generating an inverse mapping {@link ManyToOneInverseMap} that can
- * be used by the graph lens using {@link ManyToOneMap#inverse(Function)}. The inverse map is a
- * bidirectional one to one map with additional non-bidirectional representative entries.
- */
-public class ManyToOneMap<K, V> {
- private final Map<K, V> forwardMap = new IdentityHashMap<>();
- private final Map<V, Set<K>> inverseMap = new IdentityHashMap<>();
- private final Map<V, K> representativeMap = new IdentityHashMap<>();
-
- public Map<K, V> getForwardMap() {
- return forwardMap;
- }
-
- public Set<K> lookupReverse(V to) {
- return inverseMap.get(to);
- }
-
- public V put(K from, V to) {
- return forwardMap.put(from, to);
- }
-
- public void putInverse(K from, V to) {
- inverseMap.computeIfAbsent(to, ignore -> new HashSet<>()).add(from);
- }
-
- public K setRepresentative(K from, V to) {
- putInverse(from, to);
- return representativeMap.put(to, from);
- }
-
- public ManyToOneInverseMap<K, V> inverse(Function<Set<K>, K> pickRepresentative) {
- BidirectionalOneToOneHashMap<V, K> biMap = new BidirectionalOneToOneHashMap<>();
- Map<V, K> extraMap = new HashMap<>();
- for (Entry<V, Set<K>> entry : inverseMap.entrySet()) {
- K representative = representativeMap.get(entry.getKey());
- if (entry.getValue().size() == 1) {
- K singleton = entry.getValue().iterator().next();
- assert representative == null || singleton == representative;
- if (representative == null) {
- biMap.put(entry.getKey(), singleton);
- } else {
- extraMap.put(entry.getKey(), singleton);
- }
- } else {
- if (representative == null) {
- representative = pickRepresentative.apply(entry.getValue());
- } else {
- assert representative == entry.getKey() || entry.getValue().contains(representative);
- }
- extraMap.put(entry.getKey(), representative);
- }
- }
-
- return new ManyToOneInverseMap<>(biMap, extraMap);
- }
-
- public <NewV> ManyToOneMap<K, NewV> remap(
- BiMap<V, NewV> biMap, Function<V, NewV> notInBiMap, Function<V, K> notInForwardMap) {
- ManyToOneMap<K, NewV> newMap = new ManyToOneMap<>();
-
- // All entries that should be remapped and are already in the forward and/or inverse mappings
- // should only be remapped in the directions they are already mapped in.
- BiMap<V, NewV> biMapCopy = HashBiMap.create(biMap);
- for (Entry<V, Set<K>> entry : inverseMap.entrySet()) {
- NewV to = biMapCopy.remove(entry.getKey());
- if (to == null) {
- to = biMap.getOrDefault(entry.getKey(), notInBiMap.apply(entry.getKey()));
- }
- newMap.inverseMap.put(to, entry.getValue());
- }
- for (Entry<K, V> entry : forwardMap.entrySet()) {
- NewV newTo = biMapCopy.remove(entry.getValue());
- if (newTo == null) {
- newTo = biMap.getOrDefault(entry.getValue(), notInBiMap.apply(entry.getValue()));
- }
- newMap.forwardMap.put(entry.getKey(), newTo);
- }
-
- // All new entries should be mapped in both directions.
- for (Entry<V, NewV> entry : biMapCopy.entrySet()) {
- newMap.forwardMap.put(notInForwardMap.apply(entry.getKey()), entry.getValue());
- newMap
- .inverseMap
- .computeIfAbsent(entry.getValue(), ignore -> new HashSet<>())
- .add(notInForwardMap.apply(entry.getKey()));
- }
-
- // Representatives are always in the inverse mapping, so they should always be remapped as new
- // representatives.
- for (Entry<V, K> entry : representativeMap.entrySet()) {
- NewV newTo = biMap.get(entry.getKey());
- if (newTo == null) {
- newTo = notInBiMap.apply(entry.getKey());
- }
- newMap.representativeMap.put(newTo, entry.getValue());
- }
-
- return newMap;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/Policy.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/Policy.java
index f6b86a3..4642229 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/Policy.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/Policy.java
@@ -12,6 +12,8 @@
/** Counter keeping track of how many classes this policy has removed. For debugging only. */
public int numberOfRemovedClasses;
+ public void clear() {}
+
public boolean shouldSkipPolicy() {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java
index b2fdb3d..14b249a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java
@@ -70,6 +70,8 @@
linkedGroups = applyMultiClassPolicy((MultiClassPolicy) policy, linkedGroups);
}
+ policy.clear();
+
// Any policy should not return any trivial groups.
assert linkedGroups.stream().allMatch(group -> group.size() >= 2);
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/SyntheticArgumentClass.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/SyntheticArgumentClass.java
index b6e1f53..c3aa3c0 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/SyntheticArgumentClass.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/SyntheticArgumentClass.java
@@ -107,7 +107,9 @@
boolean requiresMainDex = appView.appInfo().getMainDexClasses().containsAnyOf(mergeClasses);
List<DexType> syntheticArgumentTypes = new ArrayList<>();
- for (int i = 0; i < appView.options().horizontalClassMergingSyntheticArgumentCount; i++) {
+ for (int i = 0;
+ i < appView.options().horizontalClassMergerOptions().getSyntheticArgumentCount();
+ i++) {
syntheticArgumentTypes.add(
synthesizeClass(appView, appBuilder, context, requiresMainDex, i));
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
index da61076..0f85054 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
@@ -45,8 +45,6 @@
private final FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder;
private final AppView<AppInfoWithLiveness> appView;
private final DexItemFactory dexItemFactory;
- private final BiMap<DexMethod, DexMethod> movedMethods = HashBiMap.create();
- private final BiMap<DexField, DexField> movedFields = HashBiMap.create();
private final SyntheticArgumentClass syntheticArgumentClass;
private final BiMap<DexMethodSignature, DexMethodSignature> reservedInterfaceSignatures =
HashBiMap.create();
@@ -128,10 +126,6 @@
for (DexProgramClass root : subtypingForrest.getProgramRoots()) {
subtypingForrest.traverseNodeDepthFirst(root, HashBiMap.create(), this::fixupProgramClass);
}
-
- lensBuilder.remapMethods(movedMethods);
- lensBuilder.remapFields(movedFields);
-
HorizontalClassMergerGraphLens lens = lensBuilder.build(appView, mergedClasses);
fieldAccessChangesBuilder.build(this::fixupMethodReference).modify(appView);
new AnnotationFixer(lens).run(appView.appInfo().classes());
@@ -164,6 +158,8 @@
fixupFields(clazz.staticFields(), clazz::setStaticField);
fixupFields(clazz.instanceFields(), clazz::setInstanceField);
+ lensBuilder.commitPendingUpdates();
+
return remappedClassVirtualMethods;
}
@@ -173,7 +169,7 @@
// Don't process this method if it does not refer to a merge class type.
boolean referencesMergeClass =
Iterables.any(
- originalMethodReference.proto.getBaseTypes(dexItemFactory),
+ originalMethodReference.getProto().getBaseTypes(dexItemFactory),
mergedClasses::hasBeenMergedOrIsMergeTarget);
if (!referencesMergeClass) {
return method;
@@ -200,8 +196,7 @@
DexMethod newMethodReference =
newMethodSignature.withHolder(originalMethodReference, dexItemFactory);
- movedMethods.put(originalMethodReference, newMethodReference);
-
+ lensBuilder.fixupMethod(originalMethodReference, newMethodReference);
return method.toTypeSubstitutedMethod(newMethodReference);
}
@@ -217,17 +212,17 @@
iface.getMethodCollection().replaceVirtualMethods(this::fixupVirtualInterfaceMethod);
fixupFields(iface.staticFields(), iface::setStaticField);
fixupFields(iface.instanceFields(), iface::setInstanceField);
+ lensBuilder.commitPendingUpdates();
}
private DexEncodedMethod fixupProgramMethod(
DexMethod newMethodReference, DexEncodedMethod method) {
DexMethod originalMethodReference = method.getReference();
-
if (newMethodReference == originalMethodReference) {
return method;
}
- movedMethods.put(originalMethodReference, newMethodReference);
+ lensBuilder.fixupMethod(originalMethodReference, newMethodReference);
DexEncodedMethod newMethod = method.toTypeSubstitutedMethod(newMethodReference);
if (newMethod.isNonPrivateVirtualMethod()) {
@@ -365,26 +360,26 @@
Set<DexField> existingFields = Sets.newIdentityHashSet();
for (int i = 0; i < fields.size(); i++) {
- DexEncodedField encodedField = fields.get(i);
- DexField field = encodedField.field;
- DexField newField = fixupFieldReference(field);
+ DexEncodedField oldField = fields.get(i);
+ DexField oldFieldReference = oldField.getReference();
+ DexField newFieldReference = fixupFieldReference(oldFieldReference);
// Rename the field if it already exists.
- if (!existingFields.add(newField)) {
- DexField template = newField;
- newField =
+ if (!existingFields.add(newFieldReference)) {
+ DexField template = newFieldReference;
+ newFieldReference =
dexItemFactory.createFreshMember(
tryName ->
Optional.of(template.withName(tryName, dexItemFactory))
.filter(tryMethod -> !existingFields.contains(tryMethod)),
- newField.name.toSourceString());
- boolean added = existingFields.add(newField);
+ newFieldReference.name.toSourceString());
+ boolean added = existingFields.add(newFieldReference);
assert added;
}
- if (newField != encodedField.field) {
- movedFields.put(field, newField);
- setter.setField(i, encodedField.toTypeSubstitutedField(newField));
+ if (newFieldReference != oldFieldReference) {
+ lensBuilder.fixupField(oldFieldReference, newFieldReference);
+ setter.setField(i, oldField.toTypeSubstitutedField(newFieldReference));
}
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java
index d6690a9..7428b92 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java
@@ -13,7 +13,6 @@
public class VirtualMethodEntryPointSynthesizedCode extends SynthesizedCode {
private final Int2ReferenceSortedMap<DexMethod> mappedMethods;
- private final DexField classIdField;
public VirtualMethodEntryPointSynthesizedCode(
Int2ReferenceSortedMap<DexMethod> mappedMethods,
@@ -27,7 +26,6 @@
mappedMethods, classIdField, superMethod, method, position, originalMethod));
this.mappedMethods = mappedMethods;
- this.classIdField = classIdField;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
index fe3a898..9a44de7 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -229,8 +229,7 @@
classFileVersion = Ordered.maxIgnoreNull(classFileVersion, methodVersion);
}
DexMethod newMethod = moveMethod(classMethodsBuilder, method);
- lensBuilder.mapMethod(newMethod, newMethod);
- lensBuilder.mapMethodInverse(method.getReference(), newMethod);
+ lensBuilder.recordNewMethodSignature(method.getReference(), newMethod);
classIdToMethodMap.put(classIdentifiers.getInt(method.getHolderType()), newMethod);
if (representative == null) {
representative = method;
@@ -274,16 +273,14 @@
// Map each old non-abstract method to the newly synthesized method in the graph lens.
for (ProgramMethod oldMethod : methods) {
- if (oldMethod.getDefinition().isAbstract()) {
- lensBuilder.mapMethod(oldMethod.getReference(), newMethodReference);
- } else {
- lensBuilder.moveMethod(oldMethod.getReference(), newMethodReference);
- }
+ lensBuilder.mapMethod(oldMethod.getReference(), newMethodReference);
}
- lensBuilder.recordExtraOriginalSignature(bridgeMethodReference, newMethodReference);
+
+ // Add a mapping from a synthetic name to the synthetic merged method.
+ lensBuilder.recordNewMethodSignature(bridgeMethodReference, newMethodReference);
classMethodsBuilder.addVirtualMethod(newMethod);
- fieldAccessChangesBuilder.fieldReadByMethod(group.getClassIdField(), newMethod.method);
+ fieldAccessChangesBuilder.fieldReadByMethod(group.getClassIdField(), newMethodReference);
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/IgnoreSynthetics.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/IgnoreSynthetics.java
index 78875fd..e45e2d3 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/IgnoreSynthetics.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/IgnoreSynthetics.java
@@ -19,6 +19,10 @@
@Override
public boolean canMerge(DexProgramClass program) {
- return !appView.getSyntheticItems().isSyntheticClass(program);
+ if (appView.getSyntheticItems().isSyntheticClass(program)) {
+ return appView.options().horizontalClassMergerOptions().isJavaLambdaMergingEnabled()
+ && appView.getSyntheticItems().isLegacySyntheticClass(program);
+ }
+ return true;
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitGroups.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitGroups.java
index f2800aa..33de8f3 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitGroups.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/LimitGroups.java
@@ -18,7 +18,7 @@
private final int maxGroupSize;
public LimitGroups(AppView<AppInfoWithLiveness> appView) {
- maxGroupSize = appView.options().horizontalClassMergingMaxGroupSize;
+ maxGroupSize = appView.options().horizontalClassMergerOptions().getMaxGroupSize();
assert maxGroupSize >= 2;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerWithObservableSideEffects.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerWithObservableSideEffects.java
new file mode 100644
index 0000000..f10d78c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoClassInitializerWithObservableSideEffects.java
@@ -0,0 +1,31 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.horizontalclassmerging.policies;
+
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
+
+/**
+ * Prevent merging of classes with static initializers, as merging these causes side effects. It is
+ * okay for superclasses to have static initializers as all classes are expected to have the same
+ * super class.
+ */
+public class NoClassInitializerWithObservableSideEffects extends SingleClassPolicy {
+
+ @Override
+ public boolean canMerge(DexProgramClass program) {
+ if (!program.hasClassInitializer()) {
+ return true;
+ }
+ DexEncodedMethod clinit = program.getClassInitializer();
+ return clinit.getOptimizationInfo().classInitializerMayBePostponed() || isKotlinLambda(program);
+ }
+
+ private boolean isKotlinLambda(DexProgramClass program) {
+ return program.getKotlinInfo().isSyntheticClass()
+ && program.getKotlinInfo().asSyntheticClass().isLambda();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoEnums.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoEnums.java
index 2da0177..c8a0aab 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoEnums.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoEnums.java
@@ -22,8 +22,19 @@
}
@Override
+ public void clear() {
+ cache.clear();
+ }
+
+ @Override
public boolean canMerge(DexProgramClass program) {
- return !program.isEnum() && !isEnumSubtype(program);
+ if (program.isEnum()) {
+ return false;
+ }
+ if (isEnumSubtype(program)) {
+ return false;
+ }
+ return true;
}
private boolean isEnumSubtype(DexClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinLambdas.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinLambdas.java
index a137e88..dee7a4a 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinLambdas.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKotlinLambdas.java
@@ -18,7 +18,7 @@
@Override
public boolean shouldSkipPolicy() {
- return appView.options().enableHorizontalClassMergingOfKotlinLambdas;
+ return appView.options().horizontalClassMergerOptions().isKotlinLambdaMergingEnabled();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoStaticClassInitializer.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoStaticClassInitializer.java
deleted file mode 100644
index aeca6c0..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoStaticClassInitializer.java
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.horizontalclassmerging.policies;
-
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
-
-/**
- * Prevent merging of classes with static initializers, as merging these causes side effects. It is
- * okay for superclasses to have static initializers as all classes are expected to have the same
- * super class.
- */
-public class NoStaticClassInitializer extends SingleClassPolicy {
- @Override
- public boolean canMerge(DexProgramClass program) {
- return !program.hasClassInitializer();
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
index 8e52af1..ee985c4 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/FieldValueAnalysis.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.DominatorTree;
@@ -86,10 +87,16 @@
return null;
}
+ boolean isStaticFieldValueAnalysis() {
+ return false;
+ }
+
StaticFieldValueAnalysis asStaticFieldValueAnalysis() {
return null;
}
+ abstract boolean isSubjectToOptimizationIgnoringPinning(DexEncodedField field);
+
abstract boolean isSubjectToOptimization(DexEncodedField field);
void recordFieldPut(DexEncodedField field, Instruction instruction) {
@@ -118,9 +125,18 @@
if (instruction.isFieldPut()) {
FieldInstruction fieldPut = instruction.asFieldInstruction();
DexField field = fieldPut.getField();
- DexEncodedField encodedField = appInfo.resolveField(field).getResolvedField();
- if (encodedField != null && isSubjectToOptimization(encodedField)) {
- recordFieldPut(encodedField, fieldPut);
+ SuccessfulFieldResolutionResult fieldResolutionResult =
+ appInfo.resolveField(field).asSuccessfulResolution();
+ if (fieldResolutionResult != null) {
+ DexEncodedField encodedField = fieldResolutionResult.getResolvedField();
+ assert encodedField != null;
+ if (isSubjectToOptimization(encodedField)) {
+ recordFieldPut(encodedField, fieldPut);
+ } else if (isStaticFieldValueAnalysis()
+ && fieldResolutionResult.getResolvedHolder().isEnum()
+ && isSubjectToOptimizationIgnoringPinning(encodedField)) {
+ recordFieldPut(encodedField, fieldPut);
+ }
}
} else if (isInstanceFieldValueAnalysis()
&& instruction.isInvokeConstructor(appView.dexItemFactory())) {
@@ -153,15 +169,15 @@
boolean priorReadsWillReadSameValue =
!classInitializerDefaultsResult.hasStaticValue(field) && fieldPut.value().isZero();
if (!priorReadsWillReadSameValue && fieldMaybeReadBeforeInstruction(field, fieldPut)) {
- if (!isInstanceFieldValueAnalysis()) {
+ // TODO(b/172528424): Generalize to InstanceFieldValueAnalysis.
+ if (isStaticFieldValueAnalysis()) {
// At this point the value read in the field can be only the default static value, if read
// prior to the put, or the value put, if read after the put. We still want to record it
// because the default static value is typically null/0, so code present after a null/0
// check can take advantage of the optimization.
DexValue valueBeforePut = classInitializerDefaultsResult.getStaticValue(field);
asStaticFieldValueAnalysis()
- .updateFieldOptimizationInfoWith2Values(
- field, fieldPut, fieldPut.value(), valueBeforePut);
+ .updateFieldOptimizationInfoWith2Values(field, fieldPut.value(), valueBeforePut);
}
continue;
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
index cc607ac..c4061ec 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/InstanceFieldValueAnalysis.java
@@ -124,6 +124,11 @@
}
@Override
+ boolean isSubjectToOptimizationIgnoringPinning(DexEncodedField field) {
+ throw new Unreachable("Used by static analysis only.");
+ }
+
+ @Override
void updateFieldOptimizationInfo(DexEncodedField field, FieldInstruction fieldPut, Value value) {
if (fieldNeverWrittenBetweenInstancePutAndMethodExit(field, fieldPut.asInstancePut())) {
recordInstanceFieldIsInitializedWithValue(field, value);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
index 3ab1305..03455fb 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValueAnalysis.java
@@ -14,6 +14,7 @@
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.DexType;
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.DexValue.DexValueNull;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
@@ -42,12 +43,15 @@
public class StaticFieldValueAnalysis extends FieldValueAnalysis {
+ private final StaticFieldValues.Builder builder;
+
private StaticFieldValueAnalysis(
AppView<AppInfoWithLiveness> appView, IRCode code, OptimizationFeedback feedback) {
super(appView, code, feedback);
+ builder = StaticFieldValues.builder(code.context().getHolder());
}
- public static void run(
+ public static StaticFieldValues run(
AppView<?> appView,
IRCode code,
ClassInitializerDefaultsResult classInitializerDefaultsResult,
@@ -57,9 +61,16 @@
assert appView.enableWholeProgramOptimizations();
assert code.context().getDefinition().isClassInitializer();
timing.begin("Analyze class initializer");
- new StaticFieldValueAnalysis(appView.withLiveness(), code, feedback)
- .computeFieldOptimizationInfo(classInitializerDefaultsResult);
+ StaticFieldValues result =
+ new StaticFieldValueAnalysis(appView.withLiveness(), code, feedback)
+ .analyze(classInitializerDefaultsResult, code.context().getHolderType());
timing.end();
+ return result;
+ }
+
+ @Override
+ boolean isStaticFieldValueAnalysis() {
+ return true;
}
@Override
@@ -67,6 +78,12 @@
return this;
}
+ StaticFieldValues analyze(
+ ClassInitializerDefaultsResult classInitializerDefaultsResult, DexType holderType) {
+ computeFieldOptimizationInfo(classInitializerDefaultsResult);
+ return builder.build();
+ }
+
@Override
void computeFieldOptimizationInfo(ClassInitializerDefaultsResult classInitializerDefaultsResult) {
super.computeFieldOptimizationInfo(classInitializerDefaultsResult);
@@ -105,14 +122,32 @@
}
@Override
- void updateFieldOptimizationInfo(DexEncodedField field, FieldInstruction fieldPut, Value value) {
- // Abstract value.
- feedback.recordFieldHasAbstractValue(field, appView, getOrComputeAbstractValue(value, field));
-
- setDynamicType(field, value, false);
+ boolean isSubjectToOptimizationIgnoringPinning(DexEncodedField field) {
+ return field.isStatic()
+ && field.getHolderType() == context.getHolderType()
+ && appView
+ .appInfo()
+ .isFieldOnlyWrittenInMethodIgnoringPinning(field, context.getDefinition());
}
- private void setDynamicType(DexEncodedField field, Value value, boolean maybeNull) {
+ @Override
+ void updateFieldOptimizationInfo(DexEncodedField field, FieldInstruction fieldPut, Value value) {
+ AbstractValue abstractValue = getOrComputeAbstractValue(value, field);
+ updateFieldOptimizationInfo(field, value, abstractValue, false);
+ }
+
+ void updateFieldOptimizationInfo(
+ DexEncodedField field, Value value, AbstractValue abstractValue, boolean maybeNull) {
+ builder.recordStaticField(field, abstractValue, appView.dexItemFactory());
+
+ // We cannot modify FieldOptimizationInfo of pinned fields.
+ if (appView.appInfo().isPinned(field)) {
+ return;
+ }
+
+ // Abstract value.
+ feedback.recordFieldHasAbstractValue(field, appView, abstractValue);
+
// Dynamic upper bound type.
TypeElement fieldType =
TypeElement.fromDexType(field.field.type, Nullability.maybeNull(), appView);
@@ -137,16 +172,16 @@
}
public void updateFieldOptimizationInfoWith2Values(
- DexEncodedField field, FieldInstruction fieldPut, Value valuePut, DexValue valueBeforePut) {
+ DexEncodedField field, Value valuePut, DexValue valueBeforePut) {
// We are interested in the AbstractValue only if it's null or a value, so we can use the value
// if the code is protected by a null check.
if (valueBeforePut != DexValueNull.NULL) {
return;
}
- feedback.recordFieldHasAbstractValue(
- field, appView, NullOrAbstractValue.create(getOrComputeAbstractValue(valuePut, field)));
- setDynamicType(field, valuePut, true);
+ AbstractValue abstractValue =
+ NullOrAbstractValue.create(getOrComputeAbstractValue(valuePut, field));
+ updateFieldOptimizationInfo(field, valuePut, abstractValue, true);
}
private AbstractValue getOrComputeAbstractValue(Value value, DexEncodedField field) {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
new file mode 100644
index 0000000..b2dcdcd
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldvalueanalysis/StaticFieldValues.java
@@ -0,0 +1,143 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.analysis.fieldvalueanalysis;
+
+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.DexProgramClass;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.ObjectState;
+import com.google.common.collect.ImmutableMap;
+
+public abstract class StaticFieldValues {
+
+ public boolean isEnumStaticFieldValues() {
+ return false;
+ }
+
+ public EnumStaticFieldValues asEnumStaticFieldValues() {
+ return null;
+ }
+
+ public static Builder builder(DexProgramClass clazz) {
+ return clazz.isEnum() ? EnumStaticFieldValues.builder() : EmptyStaticValues.builder();
+ }
+
+ public abstract static class Builder {
+
+ public abstract void recordStaticField(
+ DexEncodedField staticField, AbstractValue value, DexItemFactory factory);
+
+ public abstract StaticFieldValues build();
+ }
+
+ // All the abstract values stored here may match a pinned field, using them requires therefore
+ // to check the field is not pinned or prove it is no longer pinned.
+ public static class EnumStaticFieldValues extends StaticFieldValues {
+ private final ImmutableMap<DexField, AbstractValue> enumAbstractValues;
+ private final DexField valuesField;
+ private final AbstractValue valuesAbstractValue;
+
+ public EnumStaticFieldValues(
+ ImmutableMap<DexField, AbstractValue> enumAbstractValues,
+ DexField valuesField,
+ AbstractValue valuesAbstractValue) {
+ this.enumAbstractValues = enumAbstractValues;
+ this.valuesField = valuesField;
+ this.valuesAbstractValue = valuesAbstractValue;
+ }
+
+ static StaticFieldValues.Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder extends StaticFieldValues.Builder {
+ private final ImmutableMap.Builder<DexField, AbstractValue> enumAbstractValuesBuilder =
+ ImmutableMap.builder();
+ private DexField valuesFields;
+ private AbstractValue valuesAbstractValue;
+
+ Builder() {}
+
+ @Override
+ public void recordStaticField(
+ DexEncodedField staticField, AbstractValue value, DexItemFactory factory) {
+ // TODO(b/166532388): Stop relying on the values name.
+ if (staticField.getName() == factory.enumValuesFieldName) {
+ valuesFields = staticField.field;
+ valuesAbstractValue = value;
+ } else if (staticField.isEnum()) {
+ enumAbstractValuesBuilder.put(staticField.field, value);
+ }
+ }
+
+ @Override
+ public StaticFieldValues build() {
+ ImmutableMap<DexField, AbstractValue> enumAbstractValues =
+ enumAbstractValuesBuilder.build();
+ if (valuesAbstractValue == null && enumAbstractValues.isEmpty()) {
+ return EmptyStaticValues.getInstance();
+ }
+ return new EnumStaticFieldValues(enumAbstractValues, valuesFields, valuesAbstractValue);
+ }
+ }
+
+ @Override
+ public boolean isEnumStaticFieldValues() {
+ return true;
+ }
+
+ @Override
+ public EnumStaticFieldValues asEnumStaticFieldValues() {
+ return this;
+ }
+
+ public ObjectState getObjectStateForPossiblyPinnedField(DexField field) {
+ AbstractValue fieldValue = enumAbstractValues.get(field);
+ if (fieldValue == null || fieldValue.isZero()) {
+ return null;
+ }
+ if (fieldValue.isSingleFieldValue()) {
+ return fieldValue.asSingleFieldValue().getState();
+ }
+ assert fieldValue.isUnknown();
+ return ObjectState.empty();
+ }
+
+ public AbstractValue getValuesAbstractValueForPossiblyPinnedField(DexField field) {
+ assert valuesField == field || valuesAbstractValue == null;
+ return valuesAbstractValue;
+ }
+ }
+
+ public static class EmptyStaticValues extends StaticFieldValues {
+ private static EmptyStaticValues INSTANCE = new EmptyStaticValues();
+
+ private EmptyStaticValues() {}
+
+ public static EmptyStaticValues getInstance() {
+ return INSTANCE;
+ }
+
+ static StaticFieldValues.Builder builder() {
+ return new Builder();
+ }
+
+ public static class Builder extends StaticFieldValues.Builder {
+
+ @Override
+ public void recordStaticField(
+ DexEncodedField staticField, AbstractValue value, DexItemFactory factory) {
+ // Do nothing.
+ }
+
+ @Override
+ public StaticFieldValues build() {
+ return EmptyStaticValues.getInstance();
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/EnumValuesObjectState.java b/src/main/java/com/android/tools/r8/ir/analysis/value/EnumValuesObjectState.java
index f1ec89c..2d8ddc2 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/EnumValuesObjectState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/EnumValuesObjectState.java
@@ -33,6 +33,10 @@
return state[ordinal];
}
+ public int getEnumValuesSize() {
+ return state.length;
+ }
+
@Override
public boolean isEnumValuesObjectState() {
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
index 8de1c91..911174b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleFieldValue.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -23,6 +22,7 @@
import com.android.tools.r8.ir.code.StaticGet;
import com.android.tools.r8.ir.code.TypeAndLocalInfoSupplier;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
public abstract class SingleFieldValue extends SingleValue {
@@ -107,12 +107,9 @@
public SingleValue rewrittenWithLens(AppView<AppInfoWithLiveness> appView, GraphLens lens) {
AbstractValueFactory factory = appView.abstractValueFactory();
if (field.holder == field.type) {
- EnumValueInfoMap unboxedEnumInfo = appView.unboxedEnums().getEnumValueInfoMap(field.type);
- if (unboxedEnumInfo != null) {
- // Return the ordinal of the unboxed enum.
- assert unboxedEnumInfo.hasEnumValueInfo(field);
- return factory.createSingleNumberValue(
- unboxedEnumInfo.getEnumValueInfo(field).convertToInt());
+ EnumDataMap enumDataMap = appView.unboxedEnums();
+ if (enumDataMap.hasUnboxedValueFor(field)) {
+ return factory.createSingleNumberValue(enumDataMap.getUnboxedValue(field));
}
}
return factory.createSingleFieldValue(
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
index a3f8421..54354f6 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlockInstructionListIterator.java
@@ -275,6 +275,18 @@
}
@Override
+ public void replaceCurrentInstructionWithConstString(
+ AppView<?> appView, IRCode code, DexString value) {
+ if (current == null) {
+ throw new IllegalStateException();
+ }
+
+ // Replace the instruction by const-string.
+ ConstString constString = code.createStringConstant(appView, value, current.getLocalInfo());
+ replaceCurrentInstruction(constString);
+ }
+
+ @Override
public void replaceCurrentInstructionWithStaticGet(
AppView<?> appView, IRCode code, DexField field, Set<Value> affectedValues) {
if (current == null) {
@@ -451,6 +463,16 @@
return newBlock;
}
+ @Override
+ public BasicBlock splitCopyCatchHandlers(
+ IRCode code, ListIterator<BasicBlock> blockIterator, InternalOptions options) {
+ BasicBlock splitBlock = split(code, blockIterator, false);
+ assert !block.hasCatchHandlers();
+ assert splitBlock.hasCatchHandlers();
+ block.copyCatchHandlers(code, blockIterator, splitBlock, options);
+ return splitBlock;
+ }
+
private boolean canThrow(IRCode code) {
InstructionIterator iterator = code.instructionIterator();
while (iterator.hasNext()) {
diff --git a/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java
index cb33b18..d2b9ffb 100644
--- a/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/IRCodeInstructionListIterator.java
@@ -53,6 +53,12 @@
}
@Override
+ public void replaceCurrentInstructionWithConstString(
+ AppView<?> appView, IRCode code, DexString value) {
+ instructionIterator.replaceCurrentInstructionWithConstString(appView, code, value);
+ }
+
+ @Override
public void replaceCurrentInstructionWithStaticGet(
AppView<?> appView, IRCode code, DexField field, Set<Value> affectedValues) {
instructionIterator.replaceCurrentInstructionWithStaticGet(
@@ -86,6 +92,12 @@
}
@Override
+ public BasicBlock splitCopyCatchHandlers(
+ IRCode code, ListIterator<BasicBlock> blockIterator, InternalOptions options) {
+ throw new Unimplemented();
+ }
+
+ @Override
public BasicBlock inlineInvoke(
AppView<?> appView,
IRCode code,
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
index 792018b..1acdb98 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstructionListIterator.java
@@ -96,6 +96,14 @@
void replaceCurrentInstructionWithConstInt(IRCode code, int value);
+ void replaceCurrentInstructionWithConstString(AppView<?> appView, IRCode code, DexString value);
+
+ default void replaceCurrentInstructionWithConstString(
+ AppView<?> appView, IRCode code, String value) {
+ replaceCurrentInstructionWithConstString(
+ appView, code, appView.dexItemFactory().createString(value));
+ }
+
void replaceCurrentInstructionWithStaticGet(
AppView<?> appView, IRCode code, DexField field, Set<Value> affectedValues);
@@ -146,6 +154,9 @@
return split(code, null);
}
+ BasicBlock splitCopyCatchHandlers(
+ IRCode code, ListIterator<BasicBlock> blockIterator, InternalOptions options);
+
/**
* Split the block into three blocks. The first split is at the point of the {@link ListIterator}
* cursor and the second split is <code>instructions</code> after the cursor. The existing
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 6daa9a4..9d7d69b 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
@@ -30,7 +30,9 @@
import com.android.tools.r8.ir.regalloc.RegisterAllocator;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import com.google.common.collect.ImmutableList;
import java.util.BitSet;
+import java.util.Collections;
import java.util.List;
public abstract class InvokeMethod extends Invoke {
@@ -238,4 +240,30 @@
}
return false;
}
+
+ abstract static class Builder<B extends Builder<B, I>, I extends InvokeMethod>
+ extends BuilderBase<B, I> {
+
+ protected DexMethod method;
+ protected List<Value> arguments = Collections.emptyList();
+
+ public B setArguments(List<Value> arguments) {
+ assert arguments != null;
+ this.arguments = arguments;
+ return self();
+ }
+
+ public B setSingleArgument(Value argument) {
+ return setArguments(ImmutableList.of(argument));
+ }
+
+ public B setMethod(DexMethod method) {
+ this.method = method;
+ return self();
+ }
+
+ public B setMethod(DexClassAndMethod method) {
+ return setMethod(method.getReference());
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
index 3139d20..1b3aef3 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeStatic.java
@@ -27,8 +27,6 @@
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.ir.optimize.inliner.WhyAreYouNotInliningReporter;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.google.common.collect.ImmutableList;
-import java.util.Collections;
import java.util.List;
public class InvokeStatic extends InvokeMethod {
@@ -235,29 +233,7 @@
.classInitializationMayHaveSideEffectsInContext(appView, context);
}
- public static class Builder extends BuilderBase<Builder, InvokeStatic> {
-
- private DexMethod method;
- private List<Value> arguments = Collections.emptyList();
-
- public Builder setArguments(List<Value> arguments) {
- assert arguments != null;
- this.arguments = arguments;
- return this;
- }
-
- public Builder setSingleArgument(Value argument) {
- return setArguments(ImmutableList.of(argument));
- }
-
- public Builder setMethod(DexMethod method) {
- this.method = method;
- return this;
- }
-
- public Builder setMethod(DexClassAndMethod method) {
- return setMethod(method.getReference());
- }
+ public static class Builder extends InvokeMethod.Builder<Builder, InvokeStatic> {
@Override
public InvokeStatic build() {
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
index d4f737e..e063b8f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeVirtual.java
@@ -33,6 +33,10 @@
super(target, result, arguments);
}
+ public static Builder builder() {
+ return new Builder();
+ }
+
@Override
public boolean getInterfaceBit() {
return false;
@@ -167,4 +171,17 @@
return ClassInitializationAnalysis.InstructionUtils.forInvokeVirtual(
this, clazz, context, appView, mode, assumption);
}
+
+ public static class Builder extends InvokeMethod.Builder<Builder, InvokeVirtual> {
+
+ @Override
+ public InvokeVirtual build() {
+ return amend(new InvokeVirtual(method, outValue, arguments));
+ }
+
+ @Override
+ public Builder self() {
+ return this;
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
index 889089f..e6009dd 100644
--- a/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
+++ b/src/main/java/com/android/tools/r8/ir/code/LinearFlowInstructionListIterator.java
@@ -73,6 +73,12 @@
}
@Override
+ public void replaceCurrentInstructionWithConstString(
+ AppView<?> appView, IRCode code, DexString value) {
+ currentBlockIterator.replaceCurrentInstructionWithConstString(appView, code, value);
+ }
+
+ @Override
public void replaceCurrentInstructionWithStaticGet(
AppView<?> appView, IRCode code, DexField field, Set<Value> affectedValues) {
currentBlockIterator.replaceCurrentInstructionWithStaticGet(
@@ -102,6 +108,12 @@
}
@Override
+ public BasicBlock splitCopyCatchHandlers(
+ IRCode code, ListIterator<BasicBlock> blockIterator, InternalOptions options) {
+ return currentBlockIterator.splitCopyCatchHandlers(code, blockIterator, options);
+ }
+
+ @Override
public BasicBlock inlineInvoke(
AppView<?> appView,
IRCode code,
diff --git a/src/main/java/com/android/tools/r8/ir/code/Position.java b/src/main/java/com/android/tools/r8/ir/code/Position.java
index ab28d55..0d054ef 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Position.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Position.java
@@ -7,11 +7,13 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.utils.structural.StructuralItem;
+import com.android.tools.r8.utils.structural.StructuralMapping;
+import com.android.tools.r8.utils.structural.StructuralSpecification;
import com.google.common.annotations.VisibleForTesting;
-import java.util.Comparator;
import java.util.Objects;
-public class Position implements Comparable<Position> {
+public class Position implements StructuralItem<Position> {
// A no-position marker. Not having a position means the position is implicitly defined by the
// context, e.g., the marker does not materialize anything concrete.
@@ -36,6 +38,14 @@
public final DexMethod method;
public final Position callerPosition;
+ private static void specify(StructuralSpecification<Position, ?> spec) {
+ spec.withInt(p -> p.line)
+ .withNullableItem(p -> p.file)
+ .withBool(p -> p.synthetic)
+ .withNullableItem(p -> p.method)
+ .withNullableItem(p -> p.callerPosition);
+ }
+
public Position(int line, DexString file, DexMethod method, Position callerPosition) {
this(line, file, method, callerPosition, false);
assert line >= 0;
@@ -91,6 +101,16 @@
return position;
}
+ @Override
+ public Position self() {
+ return this;
+ }
+
+ @Override
+ public StructuralMapping<Position> getStructuralMapping() {
+ return Position::specify;
+ }
+
public boolean isNone() {
return line == -1;
}
@@ -128,19 +148,6 @@
return result;
}
- @Override
- public int compareTo(Position o) {
- if (this == o) {
- return 0;
- }
- return Comparator.comparingInt((Position p) -> p.line)
- .thenComparing(p -> p.file, Comparator.nullsFirst(DexString::compareTo))
- .thenComparing(p -> p.synthetic)
- .thenComparing(p -> p.method)
- .thenComparing(p -> p.callerPosition, Comparator.nullsFirst(Position::compareTo))
- .compare(this, o);
- }
-
private String toString(boolean forceMethod) {
if (isNone()) {
return "--";
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 2ef58cd..7861771 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
@@ -22,7 +22,6 @@
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexTypeList;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
@@ -33,6 +32,7 @@
import com.android.tools.r8.ir.analysis.fieldaccess.TrivialFieldAccessReprocessor;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.InstanceFieldValueAnalysis;
import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValueAnalysis;
+import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.code.AlwaysMaterializingDefinition;
import com.android.tools.r8.ir.code.AlwaysMaterializingUser;
@@ -73,6 +73,7 @@
import com.android.tools.r8.ir.optimize.ReflectionOptimizer;
import com.android.tools.r8.ir.optimize.ServiceLoaderRewriter;
import com.android.tools.r8.ir.optimize.classinliner.ClassInliner;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxer;
import com.android.tools.r8.ir.optimize.enums.EnumValueOptimizer;
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfoCollector;
@@ -487,13 +488,13 @@
// Classes which has already been through library desugaring will not go through IR
// processing again.
LibraryDesugaredChecker libraryDesugaredChecker = new LibraryDesugaredChecker(appView);
- Set<DexProgramClass> alreadyLibraryDesugared = Sets.newConcurrentHashSet();
+ Set<DexType> alreadyLibraryDesugared = Sets.newConcurrentHashSet();
ThreadUtils.processItems(
application.classes(),
clazz -> {
if (libraryDesugaredChecker.isClassLibraryDesugared(clazz)) {
if (appView.options().desugarSpecificOptions().allowAllDesugaredInput) {
- alreadyLibraryDesugared.add(clazz);
+ alreadyLibraryDesugared.add(clazz.getType());
} else {
throw new CompilationError(
"Code for "
@@ -752,7 +753,7 @@
if (enumUnboxer != null) {
enumUnboxer.unboxEnums(postMethodProcessorBuilder, executorService, feedback);
} else {
- appView.setUnboxedEnums(EnumValueInfoMapCollection.empty());
+ appView.setUnboxedEnums(EnumDataMap.empty());
}
if (!options.debug) {
new TrivialFieldAccessReprocessor(appView.withLiveness(), postMethodProcessorBuilder)
@@ -1708,16 +1709,21 @@
}
InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos = null;
+ StaticFieldValues staticFieldValues = null;
if (method.getDefinition().isInitializer()) {
if (method.getDefinition().isClassInitializer()) {
- StaticFieldValueAnalysis.run(
- appView, code, classInitializerDefaultsResult, feedback, timing);
+ staticFieldValues =
+ StaticFieldValueAnalysis.run(
+ appView, code, classInitializerDefaultsResult, feedback, timing);
} else {
instanceFieldInitializationInfos =
InstanceFieldValueAnalysis.run(
appView, code, classInitializerDefaultsResult, feedback, timing);
}
}
+ if (enumUnboxer != null) {
+ enumUnboxer.recordEnumState(method.getHolder(), staticFieldValues);
+ }
methodOptimizationInfoCollector.collectMethodOptimizationInfo(
method, code, feedback, dynamicTypeOptimization, instanceFieldInitializationInfos, timing);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
index 84fd203..1e3b81f 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/ClassProcessor.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
+import com.android.tools.r8.utils.WorkList;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.ImmutableList;
@@ -421,8 +422,39 @@
if (clazz.isNotProgramClass()) {
return;
}
+ Set<DexType> filtered = new HashSet<>(emulatedInterfaces);
+ WorkList<DexType> workList = WorkList.newIdentityWorkList();
+ for (DexType emulatedInterface : emulatedInterfaces) {
+ DexClass iface = appView.definitionFor(emulatedInterface);
+ if (iface != null) {
+ assert iface.isLibraryClass()
+ || appView.options().desugaredLibraryConfiguration.isLibraryCompilation();
+ workList.addIfNotSeen(iface.getInterfaces());
+ }
+ }
+ while (workList.hasNext()) {
+ DexType type = workList.next();
+ filtered.remove(type);
+ DexClass iface = appView.definitionFor(type);
+ if (iface == null) {
+ continue;
+ }
+ workList.addIfNotSeen(iface.getInterfaces());
+ }
+
+ for (DexType emulatedInterface : emulatedInterfaces) {
+ DexClass s = appView.definitionFor(emulatedInterface);
+ if (s != null) {
+ s = appView.definitionFor(s.superType);
+ }
+ while (s != null && s.getType() != appView.dexItemFactory().objectType) {
+ filtered.remove(s.getType());
+ s = appView.definitionFor(s.getSuperType());
+ }
+ }
+
// We need to introduce them in deterministic order for deterministic compilation.
- ArrayList<DexType> sortedEmulatedInterfaces = new ArrayList<>(emulatedInterfaces);
+ ArrayList<DexType> sortedEmulatedInterfaces = new ArrayList<>(filtered);
Collections.sort(sortedEmulatedInterfaces);
List<GenericSignature.ClassTypeSignature> extraInterfaceSignatures = new ArrayList<>();
for (DexType extraInterface : sortedEmulatedInterfaces) {
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
index 361ab4b..0159139 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
@@ -441,7 +441,7 @@
factory.createMethod(
field.holder,
factory.createProto(factory.voidType, field.type),
- factory.initMethodName);
+ factory.constructorMethodName);
return newSynthesizedMethod(
method,
Constants.ACC_PRIVATE | Constants.ACC_SYNTHETIC,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index abe232f..d73a7c1 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -49,8 +49,10 @@
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.collections.BidirectionalManyToManyRepresentativeMap;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
-import com.google.common.collect.BiMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
import com.google.common.collect.ImmutableList;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -521,17 +523,15 @@
public InterfaceProcessorNestedGraphLens(
Map<DexType, DexType> typeMap,
Map<DexMethod, DexMethod> methodMap,
- Map<DexField, DexField> fieldMap,
- BiMap<DexField, DexField> originalFieldSignatures,
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> originalMethodSignatures,
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> extraOriginalMethodSignatures,
+ BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap,
+ BidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures,
+ BidirectionalOneToOneMap<DexMethod, DexMethod> extraOriginalMethodSignatures,
GraphLens previousLens,
DexItemFactory dexItemFactory) {
super(
typeMap,
methodMap,
fieldMap,
- originalFieldSignatures,
originalMethodSignatures,
previousLens,
dexItemFactory);
@@ -601,7 +601,7 @@
public static class Builder extends NestedGraphLens.Builder {
- private final BidirectionalOneToOneHashMap<DexMethod, DexMethod>
+ private final MutableBidirectionalOneToOneMap<DexMethod, DexMethod>
extraOriginalMethodSignatures = new BidirectionalOneToOneHashMap<>();
public void recordCodeMovedToCompanionClass(DexMethod from, DexMethod to) {
@@ -613,7 +613,7 @@
@Override
public InterfaceProcessorNestedGraphLens build(
DexItemFactory dexItemFactory, GraphLens previousLens) {
- if (originalFieldSignatures.isEmpty()
+ if (fieldMap.isEmpty()
&& originalMethodSignatures.isEmpty()
&& extraOriginalMethodSignatures.isEmpty()) {
return null;
@@ -622,7 +622,6 @@
typeMap,
methodMap,
fieldMap,
- originalFieldSignatures,
originalMethodSignatures,
extraOriginalMethodSignatures,
previousLens,
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index c9e47c2..a50581e 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -33,6 +33,8 @@
import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.Invoke.Type;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.ir.synthetic.ForwardMethodSourceCode;
import com.android.tools.r8.ir.synthetic.SynthesizedCode;
import com.android.tools.r8.origin.SynthesizedOrigin;
@@ -65,6 +67,8 @@
*/
public final class LambdaClass {
+ private static final OptimizationFeedback feedback = OptimizationFeedbackSimple.getInstance();
+
final AppView<?> appView;
final LambdaRewriter rewriter;
public final DexType type;
@@ -293,6 +297,7 @@
ParameterAnnotationsList.empty(),
LambdaClassConstructorSourceCode.build(this),
true);
+ feedback.classInitializerMayBePostponed(methods[1]);
}
return methods;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
index e4d6f65..f464fdd 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
@@ -18,7 +18,6 @@
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexCallSite;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -42,10 +41,10 @@
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
import com.google.common.base.Suppliers;
-import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.ArrayList;
@@ -73,7 +72,7 @@
public static final String LAMBDA_CLASS_NAME_PREFIX = "-$$Lambda$";
public static final String LAMBDA_GROUP_CLASS_NAME_PREFIX = "-$$LambdaGroup$";
static final String EXPECTED_LAMBDA_METHOD_PREFIX = "lambda$";
- private static final String LAMBDA_INSTANCE_FIELD_NAME = "INSTANCE";
+ public static final String LAMBDA_INSTANCE_FIELD_NAME = "INSTANCE";
private final AppView<?> appView;
@@ -133,7 +132,7 @@
*/
public int desugarLambdas(ProgramMethod method, AppInfoWithClassHierarchy appInfo) {
return desugarLambdas(
- method.getDefinition(),
+ method,
callsite -> {
LambdaDescriptor descriptor = LambdaDescriptor.tryInfer(callsite, appInfo, method);
if (descriptor == null) {
@@ -145,8 +144,8 @@
// Same as above, but where lambdas are always known to exist for the call sites.
public static int desugarLambdas(
- DexEncodedMethod method, Function<DexCallSite, LambdaClass> callSites) {
- CfCode code = method.getCode().asCfCode();
+ ProgramMethod method, Function<DexCallSite, LambdaClass> callSites) {
+ CfCode code = method.getDefinition().getCode().asCfCode();
List<CfInstruction> instructions = code.getInstructions();
Supplier<List<CfInstruction>> lazyNewInstructions =
Suppliers.memoize(() -> new ArrayList<>(instructions));
@@ -439,16 +438,14 @@
LambdaRewriterLens(
Map<DexType, DexType> typeMap,
Map<DexMethod, DexMethod> methodMap,
- Map<DexField, DexField> fieldMap,
- BiMap<DexField, DexField> originalFieldSignatures,
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> originalMethodSignatures,
+ BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap,
+ BidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures,
GraphLens previousLens,
DexItemFactory dexItemFactory) {
super(
typeMap,
methodMap,
fieldMap,
- originalFieldSignatures,
originalMethodSignatures,
previousLens,
dexItemFactory);
@@ -479,7 +476,6 @@
typeMap,
methodMap,
fieldMap,
- originalFieldSignatures,
originalMethodSignatures,
previousLens,
dexItemFactory);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLens.java b/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLens.java
index 8889ec2..12418b3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLens.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestedPrivateMethodLens.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.graph.RewrittenPrototypeDescription;
import com.android.tools.r8.ir.code.Invoke.Type;
-import com.android.tools.r8.utils.collections.BidirectionalManyToManyRepresentativeMap;
+import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap;
import com.google.common.collect.ImmutableMap;
import java.util.IdentityHashMap;
import java.util.Map;
@@ -34,9 +34,8 @@
super(
ImmutableMap.of(),
methodMap,
- ImmutableMap.of(),
- null,
- BidirectionalManyToManyRepresentativeMap.empty(),
+ new EmptyBidirectionalOneToOneMap<>(),
+ new EmptyBidirectionalOneToOneMap<>(),
previousLens,
appView.dexItemFactory());
// No concurrent maps here, we do not want synchronization overhead.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
index d648bc1..f4232a2 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.ir.code.InvokeVirtual;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
@@ -47,9 +48,11 @@
public class Devirtualizer {
private final AppView<AppInfoWithLiveness> appView;
+ private final InternalOptions options;
public Devirtualizer(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
+ this.options = appView.options();
}
public void devirtualizeInvokeInterface(IRCode code) {
@@ -115,6 +118,7 @@
}
}
}
+ continue;
}
if (current.isInvokeSuper()) {
@@ -122,7 +126,7 @@
// Check if the instruction can be rewritten to invoke-super. This allows inlining of the
// enclosing method into contexts outside the current class.
- if (appView.options().testing.enableInvokeSuperToInvokeVirtualRewriting) {
+ if (options.testing.enableInvokeSuperToInvokeVirtualRewriting) {
DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
if (singleTarget != null) {
DexMethod invokedMethod = invoke.getInvokedMethod();
@@ -225,7 +229,18 @@
if (castedReceiverCache.containsKey(receiver)
&& castedReceiverCache.get(receiver).containsKey(holderClass.getType())) {
Value cachedReceiver = castedReceiverCache.get(receiver).get(holderClass.getType());
- if (dominatorTree.dominatedBy(block, cachedReceiver.definition.getBlock())) {
+ BasicBlock cachedReceiverBlock = cachedReceiver.definition.getBlock();
+ BasicBlock dominatorBlock = null;
+ if (cachedReceiverBlock.hasCatchHandlers()) {
+ if (cachedReceiverBlock.hasUniqueNormalSuccessor()) {
+ dominatorBlock = cachedReceiverBlock.getUniqueNormalSuccessor();
+ } else {
+ assert false;
+ }
+ } else {
+ dominatorBlock = cachedReceiverBlock;
+ }
+ if (dominatorBlock != null && dominatorTree.dominatedBy(block, dominatorBlock)) {
newReceiver = cachedReceiver;
}
}
@@ -245,16 +260,18 @@
// We need to add this checkcast *before* the devirtualized invoke-virtual.
assert it.peekPrevious() == devirtualizedInvoke;
it.previous();
- // If the current block has catch handlers, split the new checkcast on its own block.
- // Because checkcast is also a throwing instr, we should split before adding it.
- // Otherwise, catch handlers are bound to a block with checkcast, not invoke IR.
+
+ // If the current block has catch handlers, then split the block before adding the new
+ // check-cast instruction. The catch handlers are copied to the split block to ensure
+ // that all throwing instructions are covered by a catch-all catch handler in case of
+ // monitor instructions (see also b/174167294).
BasicBlock blockWithDevirtualizedInvoke =
- block.hasCatchHandlers() ? it.split(code, blocks) : block;
+ block.hasCatchHandlers()
+ ? it.splitCopyCatchHandlers(code, blocks, options)
+ : block;
if (blockWithDevirtualizedInvoke != block) {
// If we split, add the new checkcast at the end of the currently visiting block.
- it = block.listIterator(code, block.getInstructions().size());
- it.previous();
- it.add(checkCast);
+ block.listIterator(code, block.getInstructions().size() - 1).add(checkCast);
// Update the dominator tree after the split.
dominatorTree = new DominatorTree(code);
// Restore the cursor.
@@ -354,7 +371,11 @@
if (newResolutionResult == null
|| newResolutionResult
.isAccessibleForVirtualDispatchFrom(context, appView.appInfo())
- .isPossiblyFalse()) {
+ .isPossiblyFalse()
+ || !newResolutionResult
+ .getResolvedMethod()
+ .getAccessFlags()
+ .isAtLeastAsVisibleAs(resolutionResult.getResolvedMethod().getAccessFlags())) {
return target;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index b26bb34..96c9234 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -625,7 +625,7 @@
shouldSynthesizeMonitorEnterExit && !target.getDefinition().isStatic();
if (shouldSynthesizeNullCheckForReceiver
&& !isSynthesizingNullCheckForReceiverUsingMonitorEnter) {
- synthesizeNullCheckForReceiver(appView, code);
+ synthesizeNullCheckForReceiver(appView, code, invoke);
}
// Insert monitor-enter and monitor-exit instructions if the method is synchronized.
@@ -763,11 +763,12 @@
assert !initClassBlock.hasCatchHandlers();
InstructionListIterator iterator = initClassBlock.listIterator(code);
- iterator.setInsertionPosition(entryBlock.exit().getPosition());
+ iterator.setInsertionPosition(invoke.getPosition());
iterator.add(new InitClass(code.createValue(TypeElement.getInt()), target.getHolderType()));
}
- private void synthesizeNullCheckForReceiver(AppView<?> appView, IRCode code) {
+ private void synthesizeNullCheckForReceiver(
+ AppView<?> appView, IRCode code, InvokeMethod invoke) {
List<Value> arguments = code.collectArguments();
if (!arguments.isEmpty()) {
Value receiver = arguments.get(0);
@@ -782,7 +783,7 @@
assert !throwBlock.hasCatchHandlers();
InstructionListIterator iterator = throwBlock.listIterator(code);
- iterator.setInsertionPosition(entryBlock.exit().getPosition());
+ iterator.setInsertionPosition(invoke.getPosition());
if (appView.options().canUseRequireNonNull()) {
DexMethod requireNonNullMethod = appView.dexItemFactory().objectsMethods.requireNonNull;
iterator.add(new InvokeStatic(requireNonNullMethod, null, ImmutableList.of(receiver)));
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 8ba58f1..615e5ae 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -311,11 +311,10 @@
// Insert the definition of the replacement.
replacement.setPosition(position);
if (block.hasCatchHandlers()) {
- BasicBlock splitBlock = iterator.split(code, blocks, false);
- splitBlock.listIterator(code).add(replacement);
- assert !block.hasCatchHandlers();
- assert splitBlock.hasCatchHandlers();
- block.copyCatchHandlers(code, blocks, splitBlock, appView.options());
+ iterator
+ .splitCopyCatchHandlers(code, blocks, appView.options())
+ .listIterator(code)
+ .add(replacement);
} else {
iterator.add(replacement);
}
@@ -413,11 +412,10 @@
// Insert the definition of the replacement.
replacement.setPosition(position);
if (block.hasCatchHandlers()) {
- BasicBlock splitBlock = iterator.split(code, blocks, false);
- splitBlock.listIterator(code).add(replacement);
- assert !block.hasCatchHandlers();
- assert splitBlock.hasCatchHandlers();
- block.copyCatchHandlers(code, blocks, splitBlock, appView.options());
+ iterator
+ .splitCopyCatchHandlers(code, blocks, appView.options())
+ .listIterator(code)
+ .add(replacement);
} else {
iterator.add(replacement);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
index 3745120..cabff87 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
@@ -344,7 +344,7 @@
HorizontallyMergedClasses horizontallyMergedClasses = appView.horizontallyMergedClasses();
assert verticallyMergedClasses != null;
assert horizontallyMergedClasses != null;
- assert verticallyMergedClasses.isTarget(method.getHolderType())
+ assert verticallyMergedClasses.isMergeTarget(method.getHolderType())
|| horizontallyMergedClasses.isMergeTarget(method.getHolderType());
assert appView
.dexItemFactory()
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
index 48002cc..c681eaa 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
@@ -29,6 +29,9 @@
import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableMap;
@@ -54,14 +57,13 @@
private final Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod;
UninstantiatedTypeOptimizationGraphLens(
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> methodMap,
+ BidirectionalOneToOneMap<DexMethod, DexMethod> methodMap,
Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod,
AppView<?> appView) {
super(
ImmutableMap.of(),
- methodMap,
- ImmutableMap.of(),
- null,
+ methodMap.getForwardMap(),
+ new EmptyBidirectionalOneToOneMap<>(),
methodMap.getInverseOneToOneMap(),
appView.graphLens(),
appView.dexItemFactory());
@@ -129,7 +131,7 @@
}
Map<Wrapper<DexMethod>, Set<DexType>> changedVirtualMethods = new HashMap<>();
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> methodMapping =
+ MutableBidirectionalOneToOneMap<DexMethod, DexMethod> methodMapping =
new BidirectionalOneToOneHashMap<>();
Map<DexMethod, ArgumentInfoCollection> removedArgumentsInfoPerMethod = new IdentityHashMap<>();
@@ -140,7 +142,7 @@
processClass(
clazz,
changedVirtualMethods,
- methodMapping.getForwardBacking(),
+ methodMapping.getForwardMap(),
methodPoolCollection,
removedArgumentsInfoPerMethod));
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
index 16fb558..ec1b904 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.ArgumentUse;
import com.android.tools.r8.graph.DexEncodedMethod;
-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.DexProgramClass;
@@ -27,9 +26,10 @@
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
import com.google.common.base.Equivalence.Wrapper;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.ImmutableBiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Streams;
import java.util.BitSet;
@@ -48,7 +48,7 @@
private final AppView<AppInfoWithLiveness> appView;
private final MethodPoolCollection methodPoolCollection;
- private final BidirectionalOneToOneHashMap<DexMethod, DexMethod> methodMapping =
+ private final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> methodMapping =
new BidirectionalOneToOneHashMap<>();
private final Map<DexMethod, ArgumentInfoCollection> removedArguments = new IdentityHashMap<>();
@@ -57,19 +57,15 @@
private final Map<DexMethod, ArgumentInfoCollection> removedArguments;
UnusedArgumentsGraphLens(
- Map<DexType, DexType> typeMap,
Map<DexMethod, DexMethod> methodMap,
- Map<DexField, DexField> fieldMap,
- BiMap<DexField, DexField> originalFieldSignatures,
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> originalMethodSignatures,
+ BidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures,
GraphLens previousLens,
DexItemFactory dexItemFactory,
Map<DexMethod, ArgumentInfoCollection> removedArguments) {
super(
- typeMap,
+ ImmutableMap.of(),
methodMap,
- fieldMap,
- originalFieldSignatures,
+ new EmptyBidirectionalOneToOneMap<>(),
originalMethodSignatures,
previousLens,
dexItemFactory);
@@ -108,10 +104,7 @@
if (!methodMapping.isEmpty()) {
return new UnusedArgumentsGraphLens(
- ImmutableMap.of(),
- methodMapping,
- ImmutableMap.of(),
- ImmutableBiMap.of(),
+ methodMapping.getForwardMap(),
methodMapping.getInverseOneToOneMap(),
appView.graphLens(),
appView.dexItemFactory(),
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UtilityMethodsForCodeOptimizations.java b/src/main/java/com/android/tools/r8/ir/optimize/UtilityMethodsForCodeOptimizations.java
index 247e2e3..1b55f13 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UtilityMethodsForCodeOptimizations.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UtilityMethodsForCodeOptimizations.java
@@ -19,6 +19,35 @@
public class UtilityMethodsForCodeOptimizations {
+ public static UtilityMethodForCodeOptimizations synthesizeToStringIfNotNullMethod(
+ AppView<?> appView, ProgramMethod context, MethodProcessingId methodProcessingId) {
+ InternalOptions options = appView.options();
+ if (options.isGeneratingClassFiles()) {
+ // TODO(b/172194277): Allow synthetics when generating CF.
+ return null;
+ }
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ DexProto proto = dexItemFactory.createProto(dexItemFactory.voidType, dexItemFactory.objectType);
+ SyntheticItems syntheticItems = appView.getSyntheticItems();
+ ProgramMethod syntheticMethod =
+ syntheticItems.createMethod(
+ context,
+ dexItemFactory,
+ builder ->
+ builder
+ .setProto(proto)
+ .setAccessFlags(MethodAccessFlags.createPublicStaticSynthetic())
+ .setCode(method -> getToStringIfNotNullCodeTemplate(method, options)),
+ methodProcessingId);
+ return new UtilityMethodForCodeOptimizations(syntheticMethod);
+ }
+
+ private static CfCode getToStringIfNotNullCodeTemplate(
+ DexMethod method, InternalOptions options) {
+ return CfUtilityMethodsForCodeOptimizations
+ .CfUtilityMethodsForCodeOptimizationsTemplates_toStringIfNotNull(options, method);
+ }
+
public static UtilityMethodForCodeOptimizations synthesizeThrowClassCastExceptionIfNotNullMethod(
AppView<?> appView, ProgramMethod context, MethodProcessingId methodProcessingId) {
InternalOptions options = appView.options();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
new file mode 100644
index 0000000..07471e7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumDataMap.java
@@ -0,0 +1,109 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.enums;
+
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.util.Set;
+
+public class EnumDataMap {
+ private final ImmutableMap<DexType, EnumData> map;
+
+ public static EnumDataMap empty() {
+ return new EnumDataMap(ImmutableMap.of());
+ }
+
+ public EnumDataMap(ImmutableMap<DexType, EnumData> map) {
+ this.map = map;
+ }
+
+ public boolean isUnboxedEnum(DexType type) {
+ return map.containsKey(type);
+ }
+
+ public boolean isEmpty() {
+ return map.isEmpty();
+ }
+
+ public Set<DexType> getUnboxedEnums() {
+ return map.keySet();
+ }
+
+ public EnumInstanceFieldKnownData getInstanceFieldData(
+ DexType enumType, DexField enumInstanceField) {
+ assert map.containsKey(enumType);
+ return map.get(enumType).getInstanceFieldData(enumInstanceField);
+ }
+
+ public boolean hasUnboxedValueFor(DexField enumStaticField) {
+ return isUnboxedEnum(enumStaticField.holder)
+ && map.get(enumStaticField.holder).hasUnboxedValueFor(enumStaticField);
+ }
+
+ public int getUnboxedValue(DexField enumStaticField) {
+ assert map.containsKey(enumStaticField.holder);
+ return map.get(enumStaticField.holder).getUnboxedValue(enumStaticField);
+ }
+
+ public int getValuesSize(DexType enumType) {
+ assert map.containsKey(enumType);
+ return map.get(enumType).getValuesSize();
+ }
+
+ public boolean matchesValuesField(DexField staticField) {
+ assert map.containsKey(staticField.holder);
+ return map.get(staticField.holder).matchesValuesField(staticField);
+ }
+
+ public static class EnumData {
+ static final int INVALID_VALUES_SIZE = -1;
+
+ // Map each enum instance field to the list of field known data.
+ final ImmutableMap<DexField, EnumInstanceFieldKnownData> instanceFieldMap;
+ // Map each enum instance (static field) to the unboxed integer value.
+ final ImmutableMap<DexField, Integer> unboxedValues;
+ // Fields matching the $VALUES content and type, usually one.
+ final ImmutableSet<DexField> valuesFields;
+ // Size of the $VALUES field, if the valuesFields set is empty, set to INVALID_VALUES_SIZE.
+ final int valuesSize;
+
+ public EnumData(
+ ImmutableMap<DexField, EnumInstanceFieldKnownData> instanceFieldMap,
+ ImmutableMap<DexField, Integer> unboxedValues,
+ ImmutableSet<DexField> valuesFields,
+ int valuesSize) {
+ this.instanceFieldMap = instanceFieldMap;
+ this.unboxedValues = unboxedValues;
+ this.valuesFields = valuesFields;
+ this.valuesSize = valuesSize;
+ }
+
+ public EnumInstanceFieldKnownData getInstanceFieldData(DexField enumInstanceField) {
+ assert instanceFieldMap.containsKey(enumInstanceField);
+ return instanceFieldMap.get(enumInstanceField);
+ }
+
+ public int getUnboxedValue(DexField field) {
+ assert unboxedValues.containsKey(field);
+ return unboxedValues.get(field);
+ }
+
+ public boolean hasUnboxedValueFor(DexField field) {
+ return unboxedValues.get(field) != null;
+ }
+
+ public boolean matchesValuesField(DexField field) {
+ return valuesFields.contains(field);
+ }
+
+ public int getValuesSize() {
+ assert valuesSize != INVALID_VALUES_SIZE;
+ return valuesSize;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldData.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldData.java
index 4f4dea9..69a5179 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldData.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldData.java
@@ -4,9 +4,9 @@
package com.android.tools.r8.ir.optimize.enums;
-import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
-import java.util.Map;
+import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
+import java.util.function.BiConsumer;
/*
* My instances represent the values of an enum field for each of the enum instance.
@@ -83,9 +83,9 @@
}
public static class EnumInstanceFieldMappingData extends EnumInstanceFieldKnownData {
- private final Map<DexField, AbstractValue> mapping;
+ private final ImmutableInt2ReferenceSortedMap<AbstractValue> mapping;
- public EnumInstanceFieldMappingData(Map<DexField, AbstractValue> mapping) {
+ public EnumInstanceFieldMappingData(ImmutableInt2ReferenceSortedMap<AbstractValue> mapping) {
this.mapping = mapping;
}
@@ -104,8 +104,12 @@
return this;
}
- public AbstractValue getData(DexField field) {
- return mapping.get(field);
+ public AbstractValue getData(int unboxedEnumValue) {
+ return mapping.get(unboxedEnumValue);
+ }
+
+ public void forEach(BiConsumer<? super Integer, ? super AbstractValue> consumer) {
+ mapping.forEach(consumer);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldDataMap.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldDataMap.java
deleted file mode 100644
index f02e488..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumInstanceFieldDataMap.java
+++ /dev/null
@@ -1,27 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.ir.optimize.enums;
-
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
-import com.google.common.collect.ImmutableMap;
-
-public class EnumInstanceFieldDataMap {
- private final ImmutableMap<DexType, ImmutableMap<DexField, EnumInstanceFieldKnownData>>
- instanceFieldMap;
-
- public EnumInstanceFieldDataMap(
- ImmutableMap<DexType, ImmutableMap<DexField, EnumInstanceFieldKnownData>> instanceFieldMap) {
- this.instanceFieldMap = instanceFieldMap;
- }
-
- public EnumInstanceFieldKnownData getInstanceFieldData(
- DexType enumType, DexField enumInstanceField) {
- assert instanceFieldMap.containsKey(enumType);
- assert instanceFieldMap.get(enumType).containsKey(enumInstanceField);
- return instanceFieldMap.get(enumType).get(enumInstanceField);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index 2d46582..1ce0df3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -20,7 +20,6 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
@@ -28,10 +27,13 @@
import com.android.tools.r8.graph.ProgramPackageCollection;
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues;
+import com.android.tools.r8.ir.analysis.fieldvalueanalysis.StaticFieldValues.EnumStaticFieldValues;
import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.EnumValuesObjectState;
import com.android.tools.r8.ir.analysis.value.ObjectState;
import com.android.tools.r8.ir.code.ArrayPut;
import com.android.tools.r8.ir.code.BasicBlock;
@@ -51,6 +53,7 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.PostMethodProcessor;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap.EnumData;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldMappingData;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldOrdinalData;
@@ -64,13 +67,16 @@
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
+import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import java.util.Arrays;
-import java.util.IdentityHashMap;
import java.util.Map;
+import java.util.OptionalInt;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
@@ -86,6 +92,10 @@
private final EnumUnboxingCandidateInfoCollection enumUnboxingCandidatesInfo;
private final ProgramPackageCollection enumsToUnboxWithPackageRequirement =
ProgramPackageCollection.createEmpty();
+ private final Map<DexType, EnumStaticFieldValues> staticFieldValuesMap =
+ new ConcurrentHashMap<>();
+
+ private final DexEncodedField ordinalField;
private EnumUnboxingRewriter enumUnboxerRewriter;
@@ -104,6 +114,18 @@
}
assert !appView.options().debug;
enumUnboxingCandidatesInfo = new EnumUnboxingCandidateAnalysis(appView, this).findCandidates();
+
+ ordinalField =
+ appView.appInfo().resolveField(factory.enumMembers.ordinalField).getResolvedField();
+ if (ordinalField == null) {
+ // This can happen when compiling for non standard libraries, in that case, this effectively
+ // disables the enum unboxer.
+ enumUnboxingCandidatesInfo.clear();
+ }
+ }
+
+ public static int ordinalToUnboxedInt(int ordinal) {
+ return ordinal + 1;
}
private void markEnumAsUnboxable(Reason reason, DexProgramClass enumClass) {
@@ -351,7 +373,7 @@
ExecutorService executorService,
OptimizationFeedbackDelayed feedback)
throws ExecutionException {
- EnumInstanceFieldDataMap enumInstanceFieldDataMap = finishAnalysis();
+ EnumDataMap enumDataMap = finishAnalysis();
// At this point the enum unboxing candidates are no longer candidates, they will all be
// unboxed. We extract the now immutable enums to unbox information and clear the candidate
// info.
@@ -371,13 +393,12 @@
.synthesizeEnumUnboxingUtilityClasses(
enumClassesToUnbox, enumsToUnboxWithPackageRequirement, appBuilder)
.build();
- enumUnboxerRewriter =
- new EnumUnboxingRewriter(appView, enumsToUnbox, enumInstanceFieldDataMap, relocator);
+ enumUnboxerRewriter = new EnumUnboxingRewriter(appView, enumDataMap, relocator);
NestedGraphLens enumUnboxingLens =
new EnumUnboxingTreeFixer(appView, enumsToUnbox, relocator, enumUnboxerRewriter)
.fixupTypeReferences();
enumUnboxerRewriter.setEnumUnboxingLens(enumUnboxingLens);
- appView.setUnboxedEnums(enumUnboxerRewriter.getEnumsToUnbox());
+ appView.setUnboxedEnums(enumDataMap);
GraphLens previousLens = appView.graphLens();
appView.rewriteWithLensAndApplication(enumUnboxingLens, appBuilder.build());
updateOptimizationInfos(executorService, feedback);
@@ -426,34 +447,159 @@
keepInfo.mutate(mutator -> mutator.removeKeepInfoForPrunedItems(enumsToUnbox));
}
- public EnumInstanceFieldDataMap finishAnalysis() {
+ public EnumDataMap finishAnalysis() {
analyzeInitializers();
analyzeAccessibility();
- EnumInstanceFieldDataMap enumInstanceFieldDataMap = analyzeFields();
+ EnumDataMap enumDataMap = analyzeEnumInstances();
+ assert enumDataMap.getUnboxedEnums().size() == enumUnboxingCandidatesInfo.candidates().size();
if (debugLogEnabled) {
reportEnumsAnalysis();
}
- return enumInstanceFieldDataMap;
+ return enumDataMap;
}
- private EnumInstanceFieldDataMap analyzeFields() {
- ImmutableMap.Builder<DexType, ImmutableMap<DexField, EnumInstanceFieldKnownData>> builder =
- ImmutableMap.builder();
+ private EnumDataMap analyzeEnumInstances() {
+ ImmutableMap.Builder<DexType, EnumData> builder = ImmutableMap.builder();
enumUnboxingCandidatesInfo.forEachCandidateAndRequiredInstanceFieldData(
(enumClass, fields) -> {
- ImmutableMap.Builder<DexField, EnumInstanceFieldKnownData> typeBuilder =
- ImmutableMap.builder();
- for (DexField field : fields) {
- EnumInstanceFieldData enumInstanceFieldData = computeEnumFieldData(field, enumClass);
- if (enumInstanceFieldData.isUnknown()) {
- markEnumAsUnboxable(Reason.MISSING_INSTANCE_FIELD_DATA, enumClass);
- return;
- }
- typeBuilder.put(field, enumInstanceFieldData.asEnumFieldKnownData());
+ EnumData data = buildData(enumClass, fields);
+ if (data == null) {
+ markEnumAsUnboxable(Reason.MISSING_INSTANCE_FIELD_DATA, enumClass);
+ return;
}
- builder.put(enumClass.type, typeBuilder.build());
+ builder.put(enumClass.type, data);
});
- return new EnumInstanceFieldDataMap(builder.build());
+ staticFieldValuesMap.clear();
+ return new EnumDataMap(builder.build());
+ }
+
+ private EnumData buildData(DexProgramClass enumClass, Set<DexField> fields) {
+ // This map holds all the accessible fields to their unboxed value, so we can remap the field
+ // read to the unboxed value.
+ ImmutableMap.Builder<DexField, Integer> unboxedValues = ImmutableMap.builder();
+ // This maps the ordinal to the object state, note that some fields may have been removed,
+ // hence the entry is in this map but not the enumToOrdinalMap.
+ Int2ReferenceMap<ObjectState> ordinalToObjectState = new Int2ReferenceArrayMap<>();
+ // Any fields matching the expected $VALUES content can be recorded here, they have however
+ // all the same content.
+ ImmutableSet.Builder<DexField> valuesField = ImmutableSet.builder();
+ EnumValuesObjectState valuesContents = null;
+
+ EnumStaticFieldValues enumStaticFieldValues = staticFieldValuesMap.get(enumClass.type);
+
+ // Step 1: We iterate over the field to find direct enum instance information and the values
+ // fields.
+ for (DexEncodedField staticField : enumClass.staticFields()) {
+ if (EnumUnboxingCandidateAnalysis.isEnumField(staticField, enumClass.type)) {
+ ObjectState enumState =
+ enumStaticFieldValues.getObjectStateForPossiblyPinnedField(staticField.field);
+ if (enumState != null) {
+ OptionalInt optionalOrdinal = getOrdinal(enumState);
+ if (!optionalOrdinal.isPresent()) {
+ return null;
+ }
+ int ordinal = optionalOrdinal.getAsInt();
+ unboxedValues.put(staticField.field, ordinalToUnboxedInt(ordinal));
+ ordinalToObjectState.put(ordinal, enumState);
+ }
+ } else if (EnumUnboxingCandidateAnalysis.matchesValuesField(
+ staticField, enumClass.type, factory)) {
+ AbstractValue valuesValue =
+ enumStaticFieldValues.getValuesAbstractValueForPossiblyPinnedField(staticField.field);
+ if (valuesValue == null || valuesValue.isZero()) {
+ // Unused field
+ continue;
+ }
+ if (valuesValue.isUnknown()) {
+ return null;
+ }
+ assert valuesValue.isSingleFieldValue();
+ ObjectState valuesState = valuesValue.asSingleFieldValue().getState();
+ if (!valuesState.isEnumValuesObjectState()) {
+ return null;
+ }
+ assert valuesContents == null
+ || valuesContents.equals(valuesState.asEnumValuesObjectState());
+ valuesContents = valuesState.asEnumValuesObjectState();
+ valuesField.add(staticField.field);
+ }
+ }
+
+ // Step 2: We complete the information based on the values content, since some enum instances
+ // may be reachable only though the $VALUES field.
+ if (valuesContents != null) {
+ for (int ordinal = 0; ordinal < valuesContents.getEnumValuesSize(); ordinal++) {
+ if (!ordinalToObjectState.containsKey(ordinal)) {
+ ObjectState enumState = valuesContents.getObjectStateForOrdinal(ordinal);
+ if (enumState.isEmpty()) {
+ // If $VALUES is used, we need data for all enums, at least the ordinal.
+ return null;
+ }
+ assert getOrdinal(enumState).isPresent();
+ assert getOrdinal(enumState).getAsInt() == ordinal;
+ ordinalToObjectState.put(ordinal, enumState);
+ }
+ }
+ }
+
+ // The ordinalToObjectState map may have holes at this point, if some enum instances are never
+ // used ($VALUES unused or removed, and enum instance field unused or removed), it contains
+ // only data for reachable enum instance, that is what we're interested in.
+ ImmutableMap.Builder<DexField, EnumInstanceFieldKnownData> instanceFieldBuilder =
+ ImmutableMap.builder();
+ for (DexField instanceField : fields) {
+ EnumInstanceFieldData fieldData =
+ computeEnumFieldData(instanceField, enumClass, ordinalToObjectState);
+ if (fieldData.isUnknown()) {
+ return null;
+ }
+ instanceFieldBuilder.put(instanceField, fieldData.asEnumFieldKnownData());
+ }
+
+ return new EnumData(
+ instanceFieldBuilder.build(),
+ unboxedValues.build(),
+ valuesField.build(),
+ valuesContents == null ? EnumData.INVALID_VALUES_SIZE : valuesContents.getEnumValuesSize());
+ }
+
+ private EnumInstanceFieldData computeEnumFieldData(
+ DexField instanceField,
+ DexProgramClass enumClass,
+ Int2ReferenceMap<ObjectState> ordinalToObjectState) {
+ DexEncodedField encodedInstanceField =
+ appView.appInfo().resolveFieldOn(enumClass, instanceField).getResolvedField();
+ assert encodedInstanceField != null;
+ boolean canBeOrdinal = instanceField.type.isIntType();
+ ImmutableInt2ReferenceSortedMap.Builder<AbstractValue> data =
+ ImmutableInt2ReferenceSortedMap.builder();
+ for (Integer ordinal : ordinalToObjectState.keySet()) {
+ ObjectState state = ordinalToObjectState.get(ordinal);
+ AbstractValue fieldValue = state.getAbstractFieldValue(encodedInstanceField);
+ if (!(fieldValue.isSingleNumberValue() || fieldValue.isSingleStringValue())) {
+ return EnumInstanceFieldUnknownData.getInstance();
+ }
+ data.put(ordinalToUnboxedInt(ordinal), fieldValue);
+ if (canBeOrdinal) {
+ assert fieldValue.isSingleNumberValue();
+ int computedValue = fieldValue.asSingleNumberValue().getIntValue();
+ if (computedValue != ordinal) {
+ canBeOrdinal = false;
+ }
+ }
+ }
+ if (canBeOrdinal) {
+ return new EnumInstanceFieldOrdinalData();
+ }
+ return new EnumInstanceFieldMappingData(data.build());
+ }
+
+ private OptionalInt getOrdinal(ObjectState state) {
+ AbstractValue field = state.getAbstractFieldValue(ordinalField);
+ if (field.isSingleNumberValue()) {
+ return OptionalInt.of(field.asSingleNumberValue().getIntValue());
+ }
+ return OptionalInt.empty();
}
private void analyzeAccessibility() {
@@ -494,6 +640,17 @@
return useRegistry.computeConstraint(method.asProgramMethod(appView));
}
+ public void recordEnumState(DexProgramClass clazz, StaticFieldValues staticFieldValues) {
+ if (staticFieldValues == null || !staticFieldValues.isEnumStaticFieldValues()) {
+ return;
+ }
+ assert clazz.isEnum();
+ EnumStaticFieldValues enumStaticFieldValues = staticFieldValues.asEnumStaticFieldValues();
+ if (getEnumUnboxingCandidateOrNull(clazz.type) != null) {
+ staticFieldValuesMap.put(clazz.type, enumStaticFieldValues);
+ }
+ }
+
private class EnumAccessibilityUseRegistry extends UseRegistry {
private ProgramMethod context;
@@ -929,89 +1086,6 @@
return Reason.OTHER_UNSUPPORTED_INSTRUCTION;
}
- private EnumInstanceFieldData computeEnumFieldData(
- DexField instanceField, DexProgramClass enumClass) {
- DexEncodedField encodedInstanceField =
- appView.appInfo().resolveFieldOn(enumClass, instanceField).getResolvedField();
- assert encodedInstanceField != null;
- boolean canBeOrdinal = instanceField.type.isIntType();
- Map<DexField, AbstractValue> data = new IdentityHashMap<>();
- EnumValueInfoMapCollection.EnumValueInfoMap enumValueInfoMap =
- appView.appInfo().getEnumValueInfoMap(enumClass.type);
- for (DexField staticField : enumValueInfoMap.enumValues()) {
- ObjectState enumInstanceState =
- computeEnumInstanceObjectState(enumClass, staticField, enumValueInfoMap);
- if (enumInstanceState == null) {
- // The enum instance is effectively unused. No need to generate anything for it, the path
- // will never be taken.
- } else {
- AbstractValue fieldValue = enumInstanceState.getAbstractFieldValue(encodedInstanceField);
- if (!(fieldValue.isSingleNumberValue() || fieldValue.isSingleStringValue())) {
- return EnumInstanceFieldUnknownData.getInstance();
- }
- data.put(staticField, fieldValue);
- if (canBeOrdinal) {
- int ordinalValue = enumValueInfoMap.getEnumValueInfo(staticField).ordinal;
- assert fieldValue.isSingleNumberValue();
- int computedValue = fieldValue.asSingleNumberValue().getIntValue();
- if (computedValue != ordinalValue) {
- canBeOrdinal = false;
- }
- }
- }
- }
- if (canBeOrdinal) {
- return new EnumInstanceFieldOrdinalData();
- }
- return new EnumInstanceFieldMappingData(data);
- }
-
- // We need to access the enum instance object state to figure out if it contains known constant
- // field values. The enum instance may be accessed in two ways, directly through the enum
- // static field, or through the enum $VALUES field. If none of them are kept, the instance is
- // effectively unused. The object state may be stored in the enum static field optimization
- // info, if kept, or in the $VALUES optimization info, if kept.
- // If the enum instance is unused, this method answers null.
- private ObjectState computeEnumInstanceObjectState(
- DexProgramClass enumClass,
- DexField staticField,
- EnumValueInfoMapCollection.EnumValueInfoMap enumValueInfoMap) {
- // Attempt 1: Get object state from the instance field's optimization info.
- DexEncodedField encodedStaticField = enumClass.lookupStaticField(staticField);
- AbstractValue enumInstanceValue = encodedStaticField.getOptimizationInfo().getAbstractValue();
- if (enumInstanceValue.isSingleFieldValue()) {
- return enumInstanceValue.asSingleFieldValue().getState();
- }
- if (enumInstanceValue.isUnknown()) {
- return ObjectState.empty();
- }
- assert enumInstanceValue.isZero();
-
- // Attempt 2: Get object state from the values field's optimization info.
- DexEncodedField valuesField =
- enumClass.lookupStaticField(
- factory.createField(
- enumClass.type,
- factory.createArrayType(1, enumClass.type),
- factory.enumValuesFieldName));
- AbstractValue valuesValue = valuesField.getOptimizationInfo().getAbstractValue();
- if (valuesValue.isZero()) {
- // Unused enum instance.
- return null;
- }
- if (valuesValue.isUnknown()) {
- return ObjectState.empty();
- }
- assert valuesValue.isSingleFieldValue();
- ObjectState valuesState = valuesValue.asSingleFieldValue().getState();
- if (valuesState.isEnumValuesObjectState()) {
- return valuesState
- .asEnumValuesObjectState()
- .getObjectStateForOrdinal(enumValueInfoMap.getEnumValueInfo(staticField).ordinal);
- }
- return ObjectState.empty();
- }
-
private void reportEnumsAnalysis() {
assert debugLogEnabled;
Reporter reporter = appView.options().reporter;
@@ -1081,7 +1155,6 @@
VALUES_INVOKE,
COMPARE_TO_INVOKE,
UNSUPPORTED_LIBRARY_CALL,
- MISSING_INFO_MAP,
MISSING_INSTANCE_FIELD_DATA,
INVALID_FIELD_READ,
INVALID_FIELD_PUT,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
index b4bd339..40b0c86 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
@@ -12,7 +12,6 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxer.Reason;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.KeepInfoCollection;
@@ -54,7 +53,7 @@
if (!clazz.isEnum()) {
return false;
}
- if (!clazz.isEffectivelyFinal(appView)) {
+ if (clazz.superType != factory.enumType || !clazz.isEffectivelyFinal(appView)) {
enumUnboxer.reportFailure(clazz.type, Reason.SUBTYPES);
return false;
}
@@ -66,12 +65,6 @@
enumUnboxer.reportFailure(clazz.type, Reason.UNEXPECTED_STATIC_FIELD);
return false;
}
- EnumValueInfoMap enumValueInfoMap =
- appView.appInfo().withLiveness().getEnumValueInfoMap(clazz.type);
- if (enumValueInfoMap == null) {
- enumUnboxer.reportFailure(clazz.type, Reason.MISSING_INFO_MAP);
- return false;
- }
return true;
}
@@ -79,15 +72,9 @@
// instances.
private boolean enumHasBasicStaticFields(DexProgramClass clazz) {
for (DexEncodedField staticField : clazz.staticFields()) {
- if (staticField.field.type == clazz.type
- && staticField.accessFlags.isEnum()
- && staticField.accessFlags.isFinal()) {
+ if (isEnumField(staticField, clazz.type)) {
// Enum field, valid, do nothing.
- } else if (staticField.field.type.isArrayType()
- && staticField.field.type.toArrayElementType(factory) == clazz.type
- && staticField.accessFlags.isSynthetic()
- && staticField.accessFlags.isFinal()
- && staticField.field.name == factory.enumValuesFieldName) {
+ } else if (matchesValuesField(staticField, clazz.type, factory)) {
// Field $VALUES, valid, do nothing.
} else if (appView.appInfo().isFieldRead(staticField)) {
// Only non read static fields are valid, and they are assumed unused.
@@ -97,6 +84,21 @@
return true;
}
+ static boolean isEnumField(DexEncodedField staticField, DexType enumType) {
+ return staticField.field.type == enumType
+ && staticField.accessFlags.isEnum()
+ && staticField.accessFlags.isFinal();
+ }
+
+ static boolean matchesValuesField(
+ DexEncodedField staticField, DexType enumType, DexItemFactory factory) {
+ return staticField.field.type.isArrayType()
+ && staticField.field.type.toArrayElementType(factory) == enumType
+ && staticField.accessFlags.isSynthetic()
+ && staticField.accessFlags.isFinal()
+ && staticField.field.name == factory.enumValuesFieldName;
+ }
+
private void removeEnumsInAnnotations() {
for (DexProgramClass clazz : appView.appInfo().classes()) {
if (clazz.isAnnotation()) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
index b6660fc..f230dda 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
@@ -13,8 +13,8 @@
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import java.util.IdentityHashMap;
@@ -29,9 +29,8 @@
EnumUnboxingLens(
Map<DexType, DexType> typeMap,
Map<DexMethod, DexMethod> methodMap,
- Map<DexField, DexField> fieldMap,
- BiMap<DexField, DexField> originalFieldSignatures,
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> originalMethodSignatures,
+ BidirectionalOneToOneMap<DexField, DexField> fieldMap,
+ BidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures,
GraphLens previousLens,
DexItemFactory dexItemFactory,
Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod,
@@ -40,7 +39,6 @@
typeMap,
methodMap,
fieldMap,
- originalFieldSignatures,
originalMethodSignatures,
previousLens,
dexItemFactory);
@@ -76,8 +74,9 @@
static class Builder {
protected final Map<DexType, DexType> typeMap = new IdentityHashMap<>();
- protected final BiMap<DexField, DexField> originalFieldSignatures = HashBiMap.create();
- protected final BidirectionalOneToOneHashMap<DexMethod, DexMethod> originalMethodSignatures =
+ protected final MutableBidirectionalOneToOneMap<DexField, DexField> newFieldSignatures =
+ new BidirectionalOneToOneHashMap<>();
+ protected final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures =
new BidirectionalOneToOneHashMap<>();
private Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod =
@@ -94,7 +93,7 @@
if (from == to) {
return;
}
- originalFieldSignatures.put(to, from);
+ newFieldSignatures.put(from, to);
}
public void move(DexMethod from, DexMethod to, boolean fromStatic, boolean toStatic) {
@@ -143,16 +142,13 @@
public EnumUnboxingLens build(
DexItemFactory dexItemFactory, GraphLens previousLens, Set<DexType> unboxedEnums) {
- if (typeMap.isEmpty()
- && originalFieldSignatures.isEmpty()
- && originalMethodSignatures.isEmpty()) {
+ if (typeMap.isEmpty() && newFieldSignatures.isEmpty() && originalMethodSignatures.isEmpty()) {
return null;
}
return new EnumUnboxingLens(
typeMap,
- originalMethodSignatures.getInverseOneToOneMap(),
- originalFieldSignatures.inverse(),
- originalFieldSignatures,
+ originalMethodSignatures.getInverseOneToOneMap().getForwardMap(),
+ newFieldSignatures,
originalMethodSignatures,
previousLens,
dexItemFactory,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
index c456bd0..6c20c4f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -21,9 +21,6 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfo;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.GenericSignature.FieldTypeSignature;
import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
@@ -76,8 +73,7 @@
private final AppView<AppInfoWithLiveness> appView;
private final DexItemFactory factory;
- private final EnumValueInfoMapCollection enumsToUnbox;
- private final EnumInstanceFieldDataMap unboxedEnumsInstanceFieldData;
+ private final EnumDataMap unboxedEnumsData;
private final UnboxedEnumMemberRelocator relocator;
private NestedGraphLens enumUnboxingLens;
@@ -93,18 +89,11 @@
EnumUnboxingRewriter(
AppView<AppInfoWithLiveness> appView,
- Set<DexType> enumsToUnbox,
- EnumInstanceFieldDataMap unboxedEnumsInstanceFieldData,
+ EnumDataMap unboxedEnumsInstanceFieldData,
UnboxedEnumMemberRelocator relocator) {
this.appView = appView;
this.factory = appView.dexItemFactory();
- EnumValueInfoMapCollection.Builder builder = EnumValueInfoMapCollection.builder();
- for (DexType toUnbox : enumsToUnbox) {
- assert appView.appInfo().withLiveness().getEnumValueInfoMap(toUnbox) != null;
- builder.put(toUnbox, appView.appInfo().withLiveness().getEnumValueInfoMap(toUnbox));
- }
- this.enumsToUnbox = builder.build();
- this.unboxedEnumsInstanceFieldData = unboxedEnumsInstanceFieldData;
+ this.unboxedEnumsData = unboxedEnumsInstanceFieldData;
this.relocator = relocator;
// Custom methods for java.lang.Enum methods ordinal, equals and compareTo.
@@ -147,14 +136,10 @@
this.enumUnboxingLens = enumUnboxingLens;
}
- public EnumValueInfoMapCollection getEnumsToUnbox() {
- return enumsToUnbox;
- }
-
Set<Phi> rewriteCode(IRCode code) {
// We should not process the enum methods, they will be removed and they may contain invalid
// rewriting rules.
- if (enumsToUnbox.isEmpty()) {
+ if (unboxedEnumsData.isEmpty()) {
return Sets.newIdentityHashSet();
}
assert code.isConsistentSSABeforeTypesAreCorrect();
@@ -223,7 +208,7 @@
&& invokeStatic.getArgument(0).isConstClass()) {
DexType enumType =
invokeStatic.getArgument(0).getConstInstruction().asConstClass().getValue();
- if (enumsToUnbox.containsEnum(enumType)) {
+ if (unboxedEnumsData.isUnboxedEnum(enumType)) {
DexMethod valueOfMethod = computeValueOfUtilityMethod(enumType);
Value outValue = invokeStatic.outValue();
Value rewrittenOutValue = null;
@@ -282,17 +267,15 @@
}
if (instruction.isStaticGet()) {
StaticGet staticGet = instruction.asStaticGet();
- DexType holder = staticGet.getField().holder;
- if (enumsToUnbox.containsEnum(holder)) {
+ DexField field = staticGet.getField();
+ DexType holder = field.holder;
+ if (unboxedEnumsData.isUnboxedEnum(holder)) {
if (staticGet.outValue() == null) {
iterator.removeOrReplaceByDebugLocalRead();
continue;
}
- EnumValueInfoMap enumValueInfoMap = enumsToUnbox.getEnumValueInfoMap(holder);
- assert enumValueInfoMap != null;
affectedPhis.addAll(staticGet.outValue().uniquePhiUsers());
- EnumValueInfo enumValueInfo = enumValueInfoMap.getEnumValueInfo(staticGet.getField());
- if (enumValueInfo == null && staticGet.getField().name == factory.enumValuesFieldName) {
+ if (unboxedEnumsData.matchesValuesField(field)) {
utilityMethods.computeIfAbsent(
valuesUtilityMethod, m -> synthesizeValuesUtilityMethod());
DexField fieldValues = createValuesField(holder);
@@ -300,7 +283,9 @@
DexMethod methodValues = createValuesMethod(holder);
utilityMethods.computeIfAbsent(
methodValues,
- m -> computeValuesEncodedMethod(m, fieldValues, enumValueInfoMap.size()));
+ m ->
+ computeValuesEncodedMethod(
+ m, fieldValues, unboxedEnumsData.getValuesSize(holder)));
Value rewrittenOutValue =
code.createValue(
ArrayTypeElement.create(TypeElement.getInt(), definitelyNotNull()));
@@ -310,9 +295,10 @@
convertedEnums.put(invoke, holder);
} else {
// Replace by ordinal + 1 for null check (null is 0).
- assert enumValueInfo != null
- : "Invalid read to " + staticGet.getField().name + ", error during enum analysis";
- ConstNumber intConstant = code.createIntConstant(enumValueInfo.convertToInt());
+ assert unboxedEnumsData.hasUnboxedValueFor(field)
+ : "Invalid read to " + field.name + ", error during enum analysis";
+ ConstNumber intConstant =
+ code.createIntConstant(unboxedEnumsData.getUnboxedValue(field));
iterator.replaceCurrentInstruction(intConstant);
convertedEnums.put(intConstant, holder);
}
@@ -322,7 +308,7 @@
if (instruction.isInstanceGet()) {
InstanceGet instanceGet = instruction.asInstanceGet();
DexType holder = instanceGet.getField().holder;
- if (enumsToUnbox.containsEnum(holder)) {
+ if (unboxedEnumsData.isUnboxedEnum(holder)) {
DexMethod fieldMethod = computeInstanceFieldMethod(instanceGet.getField());
Value rewrittenOutValue =
code.createValue(
@@ -332,7 +318,7 @@
new InvokeStatic(
fieldMethod, rewrittenOutValue, ImmutableList.of(instanceGet.object()));
iterator.replaceCurrentInstruction(invoke);
- if (enumsToUnbox.containsEnum(instanceGet.getField().type)) {
+ if (unboxedEnumsData.isUnboxedEnum(instanceGet.getField().type)) {
convertedEnums.put(invoke, instanceGet.getField().type);
}
}
@@ -393,7 +379,7 @@
private DexMethod computeInstanceFieldMethod(DexField field) {
EnumInstanceFieldKnownData enumFieldKnownData =
- unboxedEnumsInstanceFieldData.getInstanceFieldData(field.holder, field);
+ unboxedEnumsData.getInstanceFieldData(field.holder, field);
if (enumFieldKnownData.isOrdinal()) {
utilityMethods.computeIfAbsent(ordinalUtilityMethod, m -> synthesizeOrdinalMethod());
return ordinalUtilityMethod;
@@ -437,7 +423,7 @@
return null;
}
DexType enumType = type.asClassType().getClassType();
- return enumsToUnbox.containsEnum(enumType) ? enumType : null;
+ return unboxedEnumsData.isUnboxedEnum(enumType) ? enumType : null;
}
public String compatibleName(DexType type) {
@@ -478,7 +464,7 @@
}
private DexMethod computeInstanceFieldUtilityMethod(DexType enumType, DexField field) {
- assert enumsToUnbox.containsEnum(enumType);
+ assert unboxedEnumsData.isUnboxedEnum(enumType);
assert field.holder == enumType || field.holder == factory.enumType;
String methodName =
"get"
@@ -498,7 +484,7 @@
private DexMethod computeStringValueOfUtilityMethod(DexType enumType) {
// TODO(b/167994636): remove duplication between instance field name read and this method.
- assert enumsToUnbox.containsEnum(enumType);
+ assert unboxedEnumsData.isUnboxedEnum(enumType);
String methodName = "string$valueOf$" + compatibleName(enumType);
DexMethod fieldMethod =
factory.createMethod(
@@ -514,7 +500,7 @@
}
private DexMethod computeValueOfUtilityMethod(DexType enumType) {
- assert enumsToUnbox.containsEnum(enumType);
+ assert unboxedEnumsData.isUnboxedEnum(enumType);
DexMethod valueOf =
factory.createMethod(
relocator.getNewMemberLocationFor(enumType),
@@ -538,7 +524,7 @@
return null;
}
DexType classType = baseType.asClassType().getClassType();
- return enumsToUnbox.containsEnum(classType) ? classType : null;
+ return unboxedEnumsData.isUnboxedEnum(classType) ? classType : null;
}
void synthesizeEnumUnboxingUtilityMethods(IRConverter converter, ExecutorService executorService)
@@ -593,16 +579,13 @@
private DexEncodedMethod synthesizeInstanceFieldMethod(
DexMethod method, DexType enumType, DexField field, AbstractValue nullValue) {
assert method.proto.returnType == field.type;
- assert unboxedEnumsInstanceFieldData.getInstanceFieldData(enumType, field).isMapping();
+ assert unboxedEnumsData.getInstanceFieldData(enumType, field).isMapping();
CfCode cfCode =
new EnumUnboxingCfCodeProvider.EnumUnboxingInstanceFieldCfCodeProvider(
appView,
method.holder,
field.type,
- enumsToUnbox.getEnumValueInfoMap(enumType),
- unboxedEnumsInstanceFieldData
- .getInstanceFieldData(enumType, field)
- .asEnumFieldMappingData(),
+ unboxedEnumsData.getInstanceFieldData(enumType, field).asEnumFieldMappingData(),
nullValue)
.generateCfCode();
return synthesizeUtilityMethod(cfCode, method, false);
@@ -610,7 +593,7 @@
private DexEncodedMethod synthesizeValueOfUtilityMethod(DexMethod method, DexType enumType) {
assert method.proto.returnType == factory.intType;
- assert unboxedEnumsInstanceFieldData
+ assert unboxedEnumsData
.getInstanceFieldData(enumType, factory.enumMembers.nameField)
.isMapping();
CfCode cfCode =
@@ -618,8 +601,7 @@
appView,
method.holder,
enumType,
- enumsToUnbox.getEnumValueInfoMap(enumType),
- unboxedEnumsInstanceFieldData
+ unboxedEnumsData
.getInstanceFieldData(enumType, factory.enumMembers.nameField)
.asEnumFieldMappingData())
.generateCfCode();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueInfoMapCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueInfoMapCollector.java
deleted file mode 100644
index c94be2e..0000000
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumValueInfoMapCollector.java
+++ /dev/null
@@ -1,94 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.ir.optimize.enums;
-
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexField;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfo;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.ir.code.IRCode;
-import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.InvokeDirect;
-import com.android.tools.r8.ir.code.StaticPut;
-import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import java.util.LinkedHashMap;
-
-/**
- * Extracts the ordinal values and any anonymous subtypes for all Enum classes from their static
- * initializer.
- *
- * <p>An Enum class has a field for each value. In the class initializer, each field is initialized
- * to a singleton object that represents the value. This code matches on the corresponding call to
- * the constructor (instance initializer) and extracts the value of the second argument, which is
- * the ordinal and the holder which is the concrete type.
- */
-public class EnumValueInfoMapCollector {
-
- private final AppView<AppInfoWithLiveness> appView;
-
- private final EnumValueInfoMapCollection.Builder valueInfoMapsBuilder =
- EnumValueInfoMapCollection.builder();
-
- public EnumValueInfoMapCollector(AppView<AppInfoWithLiveness> appView) {
- this.appView = appView;
- }
-
- public AppInfoWithLiveness run() {
- for (DexProgramClass clazz : appView.appInfo().classes()) {
- processClasses(clazz);
- }
- EnumValueInfoMapCollection valueInfoMaps = valueInfoMapsBuilder.build();
- if (!valueInfoMaps.isEmpty()) {
- return appView.appInfo().withEnumValueInfoMaps(valueInfoMaps);
- }
- return appView.appInfo();
- }
-
- private void processClasses(DexProgramClass clazz) {
- // Enum classes are flagged as such. Also, for library classes, the ordinals are not known.
- if (!clazz.accessFlags.isEnum() || clazz.isNotProgramClass() || !clazz.hasClassInitializer()) {
- return;
- }
- ProgramMethod initializer = clazz.getProgramClassInitializer();
- IRCode code = initializer.buildIR(appView);
- LinkedHashMap<DexField, EnumValueInfo> enumValueInfoMap = new LinkedHashMap<>();
- for (StaticPut staticPut : code.<StaticPut>instructions(Instruction::isStaticPut)) {
- if (staticPut.getField().type != clazz.type) {
- continue;
- }
- Instruction newInstance = staticPut.value().definition;
- if (newInstance == null || !newInstance.isNewInstance()) {
- continue;
- }
- Instruction ordinal = null;
- DexType type = null;
- for (Instruction ctorCall : newInstance.outValue().uniqueUsers()) {
- if (!ctorCall.isInvokeDirect()) {
- continue;
- }
- InvokeDirect invoke = ctorCall.asInvokeDirect();
- if (!appView.dexItemFactory().isConstructor(invoke.getInvokedMethod())
- || invoke.arguments().size() < 3) {
- continue;
- }
- ordinal = invoke.arguments().get(2).definition;
- type = invoke.getInvokedMethod().holder;
- break;
- }
- if (ordinal == null || !ordinal.isConstNumber() || type == null) {
- return;
- }
-
- EnumValueInfo info = new EnumValueInfo(type, ordinal.asConstNumber().getIntValue());
- if (enumValueInfoMap.put(staticPut.getField(), info) != null) {
- return;
- }
- }
- valueInfoMapsBuilder.put(clazz.type, new EnumValueInfoMap(enumValueInfoMap));
- }
-}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index 09c4a5d..4e3fb01 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -1076,6 +1076,7 @@
assert !context.getHolderType().isD8R8SynthesizedLambdaClassType()
|| options.debug
|| appView.appInfo().hasPinnedInstanceInitializer(context.getHolderType())
+ || appView.options().horizontalClassMergerOptions().isJavaLambdaMergingEnabled()
: "Unexpected observable side effects from lambda `" + context.toSourceString() + "`";
}
return;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
index 5840ea6..f0d7c28 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -195,6 +195,6 @@
@Override
public void classInitializerMayBePostponed(DexEncodedMethod method) {
- // Ignored.
+ method.getMutableOptimizationInfo().markClassInitializerMayBePostponed();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
index 7e78f27..262671f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/field/InstanceFieldTypeInitializationInfo.java
@@ -5,10 +5,10 @@
package com.android.tools.r8.ir.optimize.info.field;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.Objects;
@@ -49,14 +49,14 @@
@Override
public InstanceFieldInitializationInfo rewrittenWithLens(
AppView<AppInfoWithLiveness> appView, GraphLens lens) {
- EnumValueInfoMapCollection unboxedEnums = appView.unboxedEnums();
+ EnumDataMap enumDataMap = appView.unboxedEnums();
if (dynamicLowerBoundType != null
- && unboxedEnums.containsEnum(dynamicLowerBoundType.getClassType())) {
+ && enumDataMap.isUnboxedEnum(dynamicLowerBoundType.getClassType())) {
// No point in tracking the type of primitives.
return UnknownInstanceFieldInitializationInfo.getInstance();
}
if (dynamicUpperBoundType.isClassType()
- && unboxedEnums.containsEnum(dynamicUpperBoundType.asClassType().getClassType())) {
+ && enumDataMap.isUnboxedEnum(dynamicUpperBoundType.asClassType().getClassType())) {
// No point in tracking the type of primitives.
return UnknownInstanceFieldInitializationInfo.getInstance();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
index 69bdef8..2c93f77 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/BooleanMethodOptimizer.java
@@ -19,7 +19,7 @@
import com.android.tools.r8.ir.code.Value;
import java.util.Set;
-public class BooleanMethodOptimizer implements LibraryMethodModelCollection {
+public class BooleanMethodOptimizer extends StatelessLibraryMethodModelCollection {
private final AppView<?> appView;
private final DexItemFactory dexItemFactory;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java
index 4323220..5ee7017 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/EnumMethodOptimizer.java
@@ -19,7 +19,8 @@
import com.android.tools.r8.ir.code.Value;
import java.util.Set;
-public class EnumMethodOptimizer implements LibraryMethodModelCollection {
+public class EnumMethodOptimizer extends StatelessLibraryMethodModelCollection {
+
private final AppView<?> appView;
EnumMethodOptimizer(AppView<?> appView) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
index d6c8ada..25916f9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMemberOptimizer.java
@@ -35,7 +35,7 @@
/** The library types that are modeled. */
private final Set<DexType> modeledLibraryTypes = Sets.newIdentityHashSet();
- private final Map<DexType, LibraryMethodModelCollection> libraryMethodModelCollections =
+ private final Map<DexType, LibraryMethodModelCollection<?>> libraryMethodModelCollections =
new IdentityHashMap<>();
public LibraryMemberOptimizer(AppView<?> appView) {
@@ -43,6 +43,7 @@
register(new BooleanMethodOptimizer(appView));
register(new ObjectMethodOptimizer(appView));
register(new ObjectsMethodOptimizer(appView));
+ register(new StringBuilderMethodOptimizer(appView));
register(new StringMethodOptimizer(appView));
if (appView.enableWholeProgramOptimizations()) {
// Subtyping is required to prove the enum class is a subtype of java.lang.Enum.
@@ -98,9 +99,9 @@
return modeledLibraryTypes.contains(type);
}
- private void register(LibraryMethodModelCollection optimizer) {
+ private void register(LibraryMethodModelCollection<?> optimizer) {
DexType modeledType = optimizer.getType();
- LibraryMethodModelCollection existing =
+ LibraryMethodModelCollection<?> existing =
libraryMethodModelCollections.put(modeledType, optimizer);
assert existing == null;
modeledLibraryTypes.add(modeledType);
@@ -114,30 +115,37 @@
MethodProcessingId methodProcessingId) {
Set<Value> affectedValues = Sets.newIdentityHashSet();
InstructionListIterator instructionIterator = code.instructionListIterator();
+ Map<LibraryMethodModelCollection<?>, LibraryMethodModelCollection.State> optimizationStates =
+ new IdentityHashMap<>();
while (instructionIterator.hasNext()) {
Instruction instruction = instructionIterator.next();
- if (instruction.isInvokeMethod()) {
- InvokeMethod invoke = instruction.asInvokeMethod();
- DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
- if (singleTarget != null) {
- optimizeInvoke(code, instructionIterator, invoke, singleTarget, affectedValues);
- }
+ if (!instruction.isInvokeMethod()) {
+ continue;
}
+
+ InvokeMethod invoke = instruction.asInvokeMethod();
+ DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, code.context());
+ if (singleTarget == null) {
+ continue;
+ }
+
+ LibraryMethodModelCollection<?> optimizer =
+ libraryMethodModelCollections.get(singleTarget.getHolderType());
+ if (optimizer == null) {
+ continue;
+ }
+
+ LibraryMethodModelCollection.State optimizationState =
+ optimizationStates.computeIfAbsent(
+ optimizer,
+ libraryMethodModelCollection ->
+ libraryMethodModelCollection.createInitialState(
+ methodProcessor, methodProcessingId));
+ optimizer.optimize(
+ code, instructionIterator, invoke, singleTarget, affectedValues, optimizationState);
}
if (!affectedValues.isEmpty()) {
new TypeAnalysis(appView).narrowing(affectedValues);
}
}
-
- private void optimizeInvoke(
- IRCode code,
- InstructionListIterator instructionIterator,
- InvokeMethod invoke,
- DexClassAndMethod singleTarget,
- Set<Value> affectedValues) {
- LibraryMethodModelCollection optimizer =
- libraryMethodModelCollections.getOrDefault(
- singleTarget.getHolderType(), NopLibraryMethodModelCollection.getInstance());
- optimizer.optimize(code, instructionIterator, invoke, singleTarget, affectedValues);
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java
index 843e9ab..5cb30b3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodModelCollection.java
@@ -10,10 +10,18 @@
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodProcessingId;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.optimize.library.LibraryMethodModelCollection.State;
import java.util.Set;
/** Used to model the behavior of library methods for optimization purposes. */
-public interface LibraryMethodModelCollection {
+public interface LibraryMethodModelCollection<T extends State> {
+
+ default T createInitialState(
+ MethodProcessor methodProcessor, MethodProcessingId methodProcessingId) {
+ return null;
+ }
/**
* The library class whose methods are being modeled by this collection of models. As an example,
@@ -30,5 +38,20 @@
InstructionListIterator instructionIterator,
InvokeMethod invoke,
DexClassAndMethod singleTarget,
- Set<Value> affectedValues);
+ Set<Value> affectedValues,
+ T state);
+
+ @SuppressWarnings("unchecked")
+ default void optimize(
+ IRCode code,
+ InstructionListIterator instructionIterator,
+ InvokeMethod invoke,
+ DexClassAndMethod singleTarget,
+ Set<Value> affectedValues,
+ Object state) {
+ optimize(code, instructionIterator, invoke, singleTarget, affectedValues, (T) state);
+ }
+
+ /** Thread local optimization state to allow caching, etc. */
+ interface State {}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodSideEffectModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodSideEffectModelCollection.java
index 55d1dc3..70ace2b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodSideEffectModelCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LibraryMethodSideEffectModelCollection.java
@@ -36,6 +36,7 @@
.put(dexItemFactory.npeMethods.initWithMessage, alwaysTrue())
.put(dexItemFactory.objectMembers.constructor, alwaysTrue())
.put(dexItemFactory.objectMembers.getClass, alwaysTrue())
+ .put(dexItemFactory.stringBuilderMethods.toString, alwaysTrue())
.put(dexItemFactory.stringMembers.hashCode, alwaysTrue());
putAll(builder, dexItemFactory.classMethods.getNames, alwaysTrue());
putAll(
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
index f8847d3..aa93f3c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/LogMethodOptimizer.java
@@ -17,7 +17,7 @@
import com.android.tools.r8.shaking.ProguardConfiguration;
import java.util.Set;
-public class LogMethodOptimizer implements LibraryMethodModelCollection {
+public class LogMethodOptimizer extends StatelessLibraryMethodModelCollection {
private static final int VERBOSE = 2;
private static final int DEBUG = 3;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java
index f852393..2eeb165 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/NopLibraryMethodModelCollection.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.ir.code.Value;
import java.util.Set;
-public class NopLibraryMethodModelCollection implements LibraryMethodModelCollection {
+public class NopLibraryMethodModelCollection extends StatelessLibraryMethodModelCollection {
private static final NopLibraryMethodModelCollection INSTANCE =
new NopLibraryMethodModelCollection();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java
index f16af45..c325500 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectMethodOptimizer.java
@@ -14,7 +14,7 @@
import com.android.tools.r8.ir.code.Value;
import java.util.Set;
-public class ObjectMethodOptimizer implements LibraryMethodModelCollection {
+public class ObjectMethodOptimizer extends StatelessLibraryMethodModelCollection {
private final DexItemFactory dexItemFactory;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
index 8fcc1ac..9d0c8c8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/ObjectsMethodOptimizer.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexItemFactory.ObjectsMethods;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstructionListIterator;
@@ -14,12 +15,17 @@
import com.android.tools.r8.ir.code.Value;
import java.util.Set;
-public class ObjectsMethodOptimizer implements LibraryMethodModelCollection {
+public class ObjectsMethodOptimizer extends StatelessLibraryMethodModelCollection {
+ private final AppView<?> appView;
private final DexItemFactory dexItemFactory;
+ private final ObjectsMethods objectsMethods;
ObjectsMethodOptimizer(AppView<?> appView) {
- this.dexItemFactory = appView.dexItemFactory();
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ this.appView = appView;
+ this.dexItemFactory = dexItemFactory;
+ this.objectsMethods = dexItemFactory.objectsMethods;
}
@Override
@@ -34,14 +40,16 @@
InvokeMethod invoke,
DexClassAndMethod singleTarget,
Set<Value> affectedValues) {
- if (dexItemFactory.objectsMethods.isRequireNonNullMethod(singleTarget.getReference())) {
+ if (objectsMethods.isRequireNonNullMethod(singleTarget.getReference())) {
optimizeRequireNonNull(instructionIterator, invoke, affectedValues);
+ } else if (singleTarget.getReference() == objectsMethods.toStringWithObject) {
+ optimizeToStringWithObject(code, instructionIterator, invoke, affectedValues);
}
}
private void optimizeRequireNonNull(
InstructionListIterator instructionIterator, InvokeMethod invoke, Set<Value> affectedValues) {
- Value inValue = invoke.inValues().get(0);
+ Value inValue = invoke.getFirstArgument();
if (inValue.getType().isDefinitelyNotNull()) {
Value outValue = invoke.outValue();
if (outValue != null) {
@@ -52,4 +60,18 @@
instructionIterator.removeOrReplaceByDebugLocalRead();
}
}
+
+ private void optimizeToStringWithObject(
+ IRCode code,
+ InstructionListIterator instructionIterator,
+ InvokeMethod invoke,
+ Set<Value> affectedValues) {
+ Value object = invoke.getFirstArgument();
+ if (object.getType().isDefinitelyNull()) {
+ instructionIterator.replaceCurrentInstructionWithConstString(appView, code, "null");
+ if (invoke.hasOutValue()) {
+ affectedValues.addAll(invoke.outValue().affectedValues());
+ }
+ }
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java
new file mode 100644
index 0000000..8b36204
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StatelessLibraryMethodModelCollection.java
@@ -0,0 +1,46 @@
+// Copyright (c) 2019, 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.optimize.library;
+
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodProcessingId;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.optimize.library.StatelessLibraryMethodModelCollection.State;
+import java.util.Set;
+
+public abstract class StatelessLibraryMethodModelCollection
+ implements LibraryMethodModelCollection<State> {
+
+ @Override
+ public final State createInitialState(
+ MethodProcessor methodProcessor, MethodProcessingId methodProcessingId) {
+ return null;
+ }
+
+ public abstract void optimize(
+ IRCode code,
+ InstructionListIterator instructionIterator,
+ InvokeMethod invoke,
+ DexClassAndMethod singleTarget,
+ Set<Value> affectedValues);
+
+ @Override
+ public final void optimize(
+ IRCode code,
+ InstructionListIterator instructionIterator,
+ InvokeMethod invoke,
+ DexClassAndMethod singleTarget,
+ Set<Value> affectedValues,
+ State state) {
+ assert state == null;
+ optimize(code, instructionIterator, invoke, singleTarget, affectedValues);
+ }
+
+ static class State implements LibraryMethodModelCollection.State {}
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java
new file mode 100644
index 0000000..9cccb5d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StringBuilderMethodOptimizer.java
@@ -0,0 +1,269 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.library;
+
+import static com.android.tools.r8.ir.code.Opcodes.INVOKE_DIRECT;
+import static com.android.tools.r8.ir.code.Opcodes.INVOKE_VIRTUAL;
+import static com.android.tools.r8.ir.code.Opcodes.NEW_INSTANCE;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexItemFactory.StringBuildingMethods;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionListIterator;
+import com.android.tools.r8.ir.code.InvokeDirect;
+import com.android.tools.r8.ir.code.InvokeMethod;
+import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
+import com.android.tools.r8.ir.code.InvokeStatic;
+import com.android.tools.r8.ir.code.InvokeVirtual;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.MethodProcessingId;
+import com.android.tools.r8.ir.conversion.MethodProcessor;
+import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations;
+import com.android.tools.r8.ir.optimize.UtilityMethodsForCodeOptimizations.UtilityMethodForCodeOptimizations;
+import com.android.tools.r8.ir.optimize.library.StringBuilderMethodOptimizer.State;
+import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.WorkList;
+import com.google.common.collect.Sets;
+import it.unimi.dsi.fastutil.objects.Reference2BooleanMap;
+import it.unimi.dsi.fastutil.objects.Reference2BooleanOpenHashMap;
+import java.util.Set;
+
+public class StringBuilderMethodOptimizer implements LibraryMethodModelCollection<State> {
+
+ private final AppView<?> appView;
+ private final DexItemFactory dexItemFactory;
+ private final InternalOptions options;
+ private final StringBuildingMethods stringBuilderMethods;
+
+ StringBuilderMethodOptimizer(AppView<?> appView) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ this.appView = appView;
+ this.dexItemFactory = dexItemFactory;
+ this.options = appView.options();
+ this.stringBuilderMethods = dexItemFactory.stringBuilderMethods;
+ }
+
+ @Override
+ public State createInitialState(
+ MethodProcessor methodProcessor, MethodProcessingId methodProcessingId) {
+ return new State(methodProcessor, methodProcessingId);
+ }
+
+ @Override
+ public DexType getType() {
+ return dexItemFactory.stringBuilderType;
+ }
+
+ @Override
+ public void optimize(
+ IRCode code,
+ InstructionListIterator instructionIterator,
+ InvokeMethod invoke,
+ DexClassAndMethod singleTarget,
+ Set<Value> affectedValues,
+ State state) {
+ if (invoke.isInvokeMethodWithReceiver()) {
+ InvokeMethodWithReceiver invokeWithReceiver = invoke.asInvokeMethodWithReceiver();
+ if (stringBuilderMethods.isAppendMethod(singleTarget.getReference())) {
+ optimizeAppend(code, instructionIterator, invokeWithReceiver, singleTarget, state);
+ }
+ }
+ }
+
+ private void optimizeAppend(
+ IRCode code,
+ InstructionListIterator instructionIterator,
+ InvokeMethodWithReceiver invoke,
+ DexClassAndMethod singleTarget,
+ State state) {
+ if (!state.isUnusedBuilder(invoke.getReceiver())) {
+ return;
+ }
+ if (invoke.hasOutValue()) {
+ invoke.outValue().replaceUsers(invoke.getReceiver());
+ }
+ DexMethod appendMethod = singleTarget.getReference();
+ if (stringBuilderMethods.isAppendPrimitiveMethod(appendMethod)
+ || stringBuilderMethods.isAppendStringMethod(appendMethod)) {
+ instructionIterator.removeOrReplaceByDebugLocalRead();
+ } else if (stringBuilderMethods.isAppendObjectMethod(appendMethod)) {
+ Value object = invoke.getArgument(1);
+ if (object.isNeverNull()) {
+ // Replace the instruction by java.lang.Object.toString().
+ instructionIterator.replaceCurrentInstruction(
+ InvokeVirtual.builder()
+ .setMethod(dexItemFactory.objectMembers.toString)
+ .setSingleArgument(object)
+ .build());
+ } else if (options.canUseJavaUtilObjects()) {
+ // Replace the instruction by java.util.Objects.toString().
+ instructionIterator.replaceCurrentInstruction(
+ InvokeStatic.builder()
+ .setMethod(dexItemFactory.objectsMethods.toStringWithObject)
+ .setSingleArgument(object)
+ .build());
+ // Allow the java.util.Objects optimizer to optimize the newly added toString().
+ instructionIterator.previous();
+ } else {
+ // Replace the instruction by toStringIfNotNull().
+ UtilityMethodForCodeOptimizations toStringIfNotNullMethod =
+ UtilityMethodsForCodeOptimizations.synthesizeToStringIfNotNullMethod(
+ appView, code.context(), state.methodProcessingId);
+ // TODO(b/172194277): Allow synthetics when generating CF.
+ if (toStringIfNotNullMethod != null) {
+ toStringIfNotNullMethod.optimize(state.methodProcessor);
+ InvokeStatic replacement =
+ InvokeStatic.builder()
+ .setMethod(toStringIfNotNullMethod.getMethod())
+ .setSingleArgument(object)
+ .build();
+ instructionIterator.replaceCurrentInstruction(replacement);
+ }
+ }
+ }
+ }
+
+ class State implements LibraryMethodModelCollection.State {
+
+ final MethodProcessor methodProcessor;
+ final MethodProcessingId methodProcessingId;
+
+ final Reference2BooleanMap<Value> unusedBuilders = new Reference2BooleanOpenHashMap<>();
+
+ State(MethodProcessor methodProcessor, MethodProcessingId methodProcessingId) {
+ this.methodProcessor = methodProcessor;
+ this.methodProcessingId = methodProcessingId;
+ }
+
+ boolean isUnusedBuilder(Value value) {
+ if (!unusedBuilders.containsKey(value)) {
+ computeIsUnusedBuilder(value);
+ assert unusedBuilders.containsKey(value);
+ }
+ return unusedBuilders.getBoolean(value);
+ }
+
+ private void computeIsUnusedBuilder(Value value) {
+ assert !unusedBuilders.containsKey(value);
+
+ Set<Value> aliases = Sets.newIdentityHashSet();
+ boolean isUnused = computeAllAliasesIfUnusedStringBuilder(value, aliases);
+ aliases.forEach(alias -> unusedBuilders.put(alias, isUnused));
+ }
+
+ /**
+ * Adds all the aliases of the given StringBuilder value to {@param aliases}, or returns false
+ * if all aliases were not found (e.g., due to a phi user).
+ */
+ private boolean computeAllAliasesIfUnusedStringBuilder(Value value, Set<Value> aliases) {
+ WorkList<Value> worklist = WorkList.newIdentityWorkList(value);
+ while (worklist.hasNext()) {
+ Value alias = worklist.next();
+ aliases.add(alias);
+
+ if (unusedBuilders.containsKey(alias)) {
+ assert !unusedBuilders.getBoolean(alias);
+ return false;
+ }
+
+ // Don't track phi aliases.
+ if (alias.hasPhiUsers()) {
+ return false;
+ }
+
+ // Analyze root, if any.
+ if (alias.isPhi()) {
+ return false;
+ }
+
+ Instruction definition = alias.definition;
+ switch (definition.opcode()) {
+ case NEW_INSTANCE:
+ assert definition.asNewInstance().clazz == dexItemFactory.stringBuilderType;
+ break;
+
+ case INVOKE_VIRTUAL:
+ {
+ InvokeVirtual invoke = definition.asInvokeVirtual();
+ if (!stringBuilderMethods.isAppendMethod(invoke.getInvokedMethod())) {
+ // Unhandled definition.
+ return false;
+ }
+ worklist.addIfNotSeen(invoke.getReceiver());
+ }
+ break;
+
+ default:
+ // Unhandled definition.
+ return false;
+ }
+
+ // Analyze all users.
+ for (Instruction user : alias.uniqueUsers()) {
+ switch (user.opcode()) {
+ case INVOKE_DIRECT:
+ {
+ InvokeDirect invoke = user.asInvokeDirect();
+
+ // Only allow invokes where the string builder value is the receiver.
+ if (invoke.arguments().lastIndexOf(alias) > 0) {
+ return false;
+ }
+
+ // Only allow invoke-direct instructions that target the string builder constructor.
+ if (!stringBuilderMethods.isConstructorMethod(invoke.getInvokedMethod())) {
+ return false;
+ }
+ }
+ break;
+
+ case INVOKE_VIRTUAL:
+ {
+ InvokeVirtual invoke = user.asInvokeVirtual();
+
+ // Only allow invokes where the string builder value is the receiver.
+ if (invoke.arguments().lastIndexOf(alias) > 0) {
+ return false;
+ }
+
+ DexMethod invokedMethod = invoke.getInvokedMethod();
+
+ // Allow calls to append(), but make sure to introduce the newly introduced alias,
+ // if append() has an out-value.
+ if (stringBuilderMethods.isAppendMethod(invokedMethod)) {
+ if (invoke.hasOutValue()) {
+ worklist.addIfNotSeen(invoke.outValue());
+ }
+ break;
+ }
+
+ // Allow calls to toString().
+ if (invokedMethod == stringBuilderMethods.toString) {
+ // Only allow unused StringBuilders.
+ if (invoke.hasOutValue() && invoke.outValue().hasNonDebugUsers()) {
+ return false;
+ }
+ break;
+ }
+
+ // Invoke to unhandled method, give up.
+ return false;
+ }
+
+ default:
+ // Unhandled user, give up.
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
index 18ad3e6..c8d04ae 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/library/StringMethodOptimizer.java
@@ -18,7 +18,7 @@
import com.android.tools.r8.ir.code.Value;
import java.util.Set;
-public class StringMethodOptimizer implements LibraryMethodModelCollection {
+public class StringMethodOptimizer extends StatelessLibraryMethodModelCollection {
private final AppView<?> appView;
private final DexItemFactory dexItemFactory;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLens.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLens.java
index fbc4c12..75a78ab 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerGraphLens.java
@@ -9,21 +9,19 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.ir.code.Invoke.Type;
-import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
-import com.google.common.collect.BiMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
import com.google.common.collect.ImmutableMap;
class ClassStaticizerGraphLens extends NestedGraphLens {
ClassStaticizerGraphLens(
AppView<?> appView,
- BiMap<DexField, DexField> fieldMapping,
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> methodMapping) {
+ BidirectionalOneToOneMap<DexField, DexField> fieldMapping,
+ BidirectionalOneToOneMap<DexMethod, DexMethod> methodMapping) {
super(
ImmutableMap.of(),
- methodMapping,
+ methodMapping.getForwardMap(),
fieldMapping,
- fieldMapping.inverse(),
methodMapping.getInverseOneToOneMap(),
appView.graphLens(),
appView.dexItemFactory());
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index 2313a5a..9d84c1f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -47,10 +47,9 @@
import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
import com.android.tools.r8.utils.collections.LongLivedProgramMethodSetBuilder;
+import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import com.google.common.collect.Streams;
@@ -738,9 +737,10 @@
}
private ProgramMethodSet staticizeMethodSymbols() {
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> methodMapping =
+ MutableBidirectionalOneToOneMap<DexMethod, DexMethod> methodMapping =
new BidirectionalOneToOneHashMap<>();
- BiMap<DexField, DexField> fieldMapping = HashBiMap.create();
+ MutableBidirectionalOneToOneMap<DexField, DexField> fieldMapping =
+ new BidirectionalOneToOneHashMap<>();
ProgramMethodSet staticizedMethods = ProgramMethodSet.create();
for (CandidateInfo candidate : classStaticizer.candidates.values()) {
@@ -803,8 +803,8 @@
DexProgramClass candidateClass,
DexType hostType,
DexProgramClass hostClass,
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> methodMapping,
- BiMap<DexField, DexField> fieldMapping) {
+ MutableBidirectionalOneToOneMap<DexMethod, DexMethod> methodMapping,
+ MutableBidirectionalOneToOneMap<DexField, DexField> fieldMapping) {
candidateToHostMapping.put(candidateClass.type, hostType);
// Process static fields.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java
index cd9fe4e..a61662c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringBuilderOptimizer.java
@@ -30,6 +30,7 @@
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeMethodWithReceiver;
import com.android.tools.r8.ir.code.InvokeVirtual;
+import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.NumberConversion;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.code.ValueType;
@@ -215,10 +216,9 @@
private Set<Value> findAllLocalBuilders() {
// During the first iteration, collect builders that are locally created.
// TODO(b/114002137): Make sure new-instance is followed by <init> before any other calls.
- for (Instruction instr : code.instructions()) {
- if (instr.isNewInstance()
- && optimizationConfiguration.isBuilderType(instr.asNewInstance().clazz)) {
- Value builder = instr.asNewInstance().dest();
+ for (NewInstance newInstance : code.<NewInstance>instructions(Instruction::isNewInstance)) {
+ if (optimizationConfiguration.isBuilderType(newInstance.clazz)) {
+ Value builder = newInstance.asNewInstance().dest();
assert !builderToStringCounts.containsKey(builder);
builderToStringCounts.put(builder, 0);
}
@@ -228,24 +228,21 @@
}
int concatenationCount = 0;
// During the second iteration, count builders' usage.
- for (Instruction instr : code.instructions()) {
- if (instr.isInvokeMethod()) {
- InvokeMethod invoke = instr.asInvokeMethod();
- DexMethod invokedMethod = invoke.getInvokedMethod();
- if (optimizationConfiguration.isAppendMethod(invokedMethod)) {
- concatenationCount++;
- // The analysis might be overwhelmed.
- if (concatenationCount > CONCATENATION_THRESHOLD) {
- return ImmutableSet.of();
- }
- } else if (optimizationConfiguration.isToStringMethod(invokedMethod)) {
- assert invoke.arguments().size() == 1;
- Value receiver = invoke.getArgument(0).getAliasedValue();
- for (Value builder : collectAllLinkedBuilders(receiver)) {
- if (builderToStringCounts.containsKey(builder)) {
- int count = builderToStringCounts.getInt(builder);
- builderToStringCounts.put(builder, count + 1);
- }
+ for (InvokeMethod invoke : code.<InvokeMethod>instructions(Instruction::isInvokeMethod)) {
+ DexMethod invokedMethod = invoke.getInvokedMethod();
+ if (optimizationConfiguration.isAppendMethod(invokedMethod)) {
+ concatenationCount++;
+ // The analysis might be overwhelmed.
+ if (concatenationCount > CONCATENATION_THRESHOLD) {
+ return ImmutableSet.of();
+ }
+ } else if (optimizationConfiguration.isToStringMethod(invokedMethod)) {
+ assert invoke.arguments().size() == 1;
+ Value receiver = invoke.getArgument(0).getAliasedValue();
+ for (Value builder : collectAllLinkedBuilders(receiver)) {
+ if (builderToStringCounts.containsKey(builder)) {
+ int count = builderToStringCounts.getInt(builder);
+ builderToStringCounts.put(builder, count + 1);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizations.java b/src/main/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizations.java
index 9484007..9625b93 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizations.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizations.java
@@ -72,4 +72,40 @@
ImmutableList.of(),
ImmutableList.of());
}
+
+ public static CfCode CfUtilityMethodsForCodeOptimizationsTemplates_toStringIfNotNull(
+ InternalOptions options, DexMethod method) {
+ CfLabel label0 = new CfLabel();
+ CfLabel label1 = new CfLabel();
+ CfLabel label2 = new CfLabel();
+ CfLabel label3 = new CfLabel();
+ return new CfCode(
+ method.holder,
+ 1,
+ 1,
+ ImmutableList.of(
+ label0,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfIf(If.Type.EQ, ValueType.OBJECT, label2),
+ label1,
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInvoke(
+ 182,
+ options.itemFactory.createMethod(
+ options.itemFactory.objectType,
+ options.itemFactory.createProto(options.itemFactory.stringType),
+ options.itemFactory.createString("toString")),
+ false),
+ new CfStackInstruction(CfStackInstruction.Opcode.Pop),
+ label2,
+ new CfFrame(
+ new Int2ReferenceAVLTreeMap<>(
+ new int[] {0},
+ new FrameType[] {FrameType.initialized(options.itemFactory.objectType)}),
+ new ArrayDeque<>(Arrays.asList())),
+ new CfReturnVoid(),
+ label3),
+ ImmutableList.of(),
+ ImmutableList.of());
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
index 2c80105..6986b3d 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
@@ -276,7 +276,7 @@
factory.createMethod(
wrapperField.holder,
factory.createProto(factory.voidType, argType),
- factory.initMethodName),
+ factory.constructorMethodName),
false));
instructions.add(new CfReturn(ValueType.fromDexType(wrapperField.holder)));
return standardCfCodeFromInstructions(instructions);
@@ -303,7 +303,7 @@
factory.createMethod(
factory.objectType,
factory.createProto(factory.voidType),
- factory.initMethodName),
+ factory.constructorMethodName),
false));
instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.holder), 0));
instructions.add(new CfLoad(ValueType.fromDexType(wrapperField.type), 1));
@@ -337,7 +337,7 @@
factory.createMethod(
factory.runtimeExceptionType,
factory.createProto(factory.voidType, factory.stringType),
- factory.initMethodName),
+ factory.constructorMethodName),
false));
instructions.add(new CfThrow());
return standardCfCodeFromInstructions(instructions);
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
index 75358f7..d21c6d9 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
@@ -28,7 +28,6 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.ValueType;
@@ -64,7 +63,6 @@
public static class EnumUnboxingInstanceFieldCfCodeProvider extends EnumUnboxingCfCodeProvider {
private final DexType returnType;
- private final EnumValueInfoMap enumValueInfoMap;
private final EnumInstanceFieldMappingData fieldDataMap;
private final AbstractValue nullValue;
@@ -72,12 +70,10 @@
AppView<?> appView,
DexType holder,
DexType returnType,
- EnumValueInfoMap enumValueInfoMap,
EnumInstanceFieldMappingData fieldDataMap,
AbstractValue nullValue) {
super(appView, holder);
this.returnType = returnType;
- this.enumValueInfoMap = enumValueInfoMap;
this.fieldDataMap = fieldDataMap;
this.nullValue = nullValue;
}
@@ -101,19 +97,16 @@
// if (i == 1) { return 10;}
// if (i == 2) { return 20;}
- enumValueInfoMap.forEach(
- (field, enumValueInfo) -> {
- AbstractValue value = fieldDataMap.getData(field);
- if (value != null) {
- CfLabel dest = new CfLabel();
- instructions.add(new CfLoad(ValueType.fromDexType(factory.intType), 0));
- instructions.add(new CfConstNumber(enumValueInfo.convertToInt(), ValueType.INT));
- instructions.add(new CfIfCmp(If.Type.NE, ValueType.INT, dest));
- addCfInstructionsForAbstractValue(instructions, value, returnType);
- instructions.add(new CfReturn(ValueType.fromDexType(returnType)));
- instructions.add(dest);
- instructions.add(new CfFrame(locals, ImmutableDeque.of()));
- }
+ fieldDataMap.forEach(
+ (unboxedEnumValue, value) -> {
+ CfLabel dest = new CfLabel();
+ instructions.add(new CfLoad(ValueType.fromDexType(factory.intType), 0));
+ instructions.add(new CfConstNumber(unboxedEnumValue, ValueType.INT));
+ instructions.add(new CfIfCmp(If.Type.NE, ValueType.INT, dest));
+ addCfInstructionsForAbstractValue(instructions, value, returnType);
+ instructions.add(new CfReturn(ValueType.fromDexType(returnType)));
+ instructions.add(dest);
+ instructions.add(new CfFrame(locals, ImmutableDeque.of()));
});
if (nullValue != null) {
@@ -132,19 +125,16 @@
public static class EnumUnboxingValueOfCfCodeProvider extends EnumUnboxingCfCodeProvider {
- private DexType enumType;
- private EnumValueInfoMap map;
+ private final DexType enumType;
private final EnumInstanceFieldMappingData fieldDataMap;
public EnumUnboxingValueOfCfCodeProvider(
AppView<?> appView,
DexType holder,
DexType enumType,
- EnumValueInfoMap map,
EnumInstanceFieldMappingData fieldDataMap) {
super(appView, holder);
this.enumType = enumType;
- this.map = map;
this.fieldDataMap = fieldDataMap;
}
@@ -180,16 +170,15 @@
// if (s.equals("A")) { return 1;}
// if (s.equals("B")) { return 2;}
- map.forEach(
- (field, enumValueInfo) -> {
+ fieldDataMap.forEach(
+ (unboxedEnumValue, value) -> {
CfLabel dest = new CfLabel();
instructions.add(new CfLoad(ValueType.fromDexType(factory.stringType), 0));
- AbstractValue value = fieldDataMap.getData(field);
addCfInstructionsForAbstractValue(instructions, value, factory.stringType);
instructions.add(
new CfInvoke(Opcodes.INVOKEVIRTUAL, factory.stringMembers.equals, false));
instructions.add(new CfIf(If.Type.EQ, ValueType.INT, dest));
- instructions.add(new CfConstNumber(enumValueInfo.convertToInt(), ValueType.INT));
+ instructions.add(new CfConstNumber(unboxedEnumValue, ValueType.INT));
instructions.add(new CfReturn(ValueType.INT));
instructions.add(dest);
instructions.add(new CfFrame(locals, ImmutableDeque.of()));
diff --git a/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java b/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
index bd8db04..8ea4e1f 100644
--- a/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
+++ b/src/main/java/com/android/tools/r8/optimize/PublicizerLens.java
@@ -10,23 +10,22 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.ir.code.Invoke.Type;
-import com.android.tools.r8.utils.collections.BidirectionalManyToManyRepresentativeMap;
+import com.android.tools.r8.utils.collections.EmptyBidirectionalOneToOneMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import java.util.Set;
final class PublicizerLens extends NestedGraphLens {
- private final AppView appView;
+ private final AppView<?> appView;
private final Set<DexMethod> publicizedMethods;
- private PublicizerLens(AppView appView, Set<DexMethod> publicizedMethods) {
+ private PublicizerLens(AppView<?> appView, Set<DexMethod> publicizedMethods) {
super(
ImmutableMap.of(),
ImmutableMap.of(),
- ImmutableMap.of(),
- null,
- BidirectionalManyToManyRepresentativeMap.empty(),
+ new EmptyBidirectionalOneToOneMap<>(),
+ new EmptyBidirectionalOneToOneMap<>(),
appView.graphLens(),
appView.dexItemFactory());
this.appView = appView;
diff --git a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingResult.java b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingResult.java
index 09a9b27..9353111 100644
--- a/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingResult.java
+++ b/src/main/java/com/android/tools/r8/optimize/bridgehoisting/BridgeHoistingResult.java
@@ -11,7 +11,8 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.utils.collections.BidirectionalManyToOneMap;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneMap;
import java.util.Set;
import java.util.function.BiConsumer;
@@ -20,8 +21,8 @@
private final AppView<AppInfoWithLiveness> appView;
// Mapping from non-hoisted bridge methods to hoisted bridge methods.
- private final BidirectionalManyToOneMap<DexMethod, DexMethod> bridgeToHoistedBridgeMap =
- new BidirectionalManyToOneMap<>();
+ private final MutableBidirectionalManyToOneMap<DexMethod, DexMethod> bridgeToHoistedBridgeMap =
+ new BidirectionalManyToOneHashMap<>();
// Mapping from non-hoisted bridge methods to the set of contexts in which they are accessed.
private final MethodAccessInfoCollection.IdentityBuilder bridgeMethodAccessInfoCollectionBuilder =
@@ -32,7 +33,7 @@
}
public void forEachHoistedBridge(BiConsumer<ProgramMethod, BridgeInfo> consumer) {
- bridgeToHoistedBridgeMap.forEach(
+ bridgeToHoistedBridgeMap.forEachManyToOneMapping(
(bridges, hoistedBridge) -> {
DexProgramClass clazz = appView.definitionForProgramType(hoistedBridge.getHolderType());
ProgramMethod method = hoistedBridge.lookupOnProgramClass(clazz);
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
index b871193..0fe63b8 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingLens.java
@@ -11,6 +11,8 @@
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
@@ -20,14 +22,13 @@
private RepackagingLens(
AppView<AppInfoWithLiveness> appView,
- BiMap<DexField, DexField> originalFieldSignatures,
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> originalMethodSignatures,
+ BidirectionalOneToOneMap<DexField, DexField> newFieldSignatures,
+ BidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures,
BiMap<DexType, DexType> originalTypes) {
super(
originalTypes.inverse(),
- originalMethodSignatures.getInverseBacking(),
- originalFieldSignatures.inverse(),
- originalFieldSignatures,
+ originalMethodSignatures.getInverseOneToOneMap().getForwardMap(),
+ newFieldSignatures,
originalMethodSignatures,
appView.graphLens(),
appView.dexItemFactory());
@@ -48,12 +49,13 @@
public static class Builder {
protected final BiMap<DexType, DexType> originalTypes = HashBiMap.create();
- protected final BiMap<DexField, DexField> originalFieldSignatures = HashBiMap.create();
- protected final BidirectionalOneToOneHashMap<DexMethod, DexMethod> originalMethodSignatures =
+ protected final MutableBidirectionalOneToOneMap<DexField, DexField> newFieldSignatures =
+ new BidirectionalOneToOneHashMap<>();
+ protected final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures =
new BidirectionalOneToOneHashMap<>();
public void recordMove(DexField from, DexField to) {
- originalFieldSignatures.put(to, from);
+ newFieldSignatures.put(from, to);
}
public void recordMove(DexMethod from, DexMethod to) {
@@ -67,7 +69,7 @@
public RepackagingLens build(AppView<AppInfoWithLiveness> appView) {
assert !originalTypes.isEmpty();
return new RepackagingLens(
- appView, originalFieldSignatures, originalMethodSignatures, originalTypes);
+ appView, newFieldSignatures, originalMethodSignatures, originalTypes);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java
index c6a2424..17d06a3 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingTreeFixer.java
@@ -81,7 +81,7 @@
DexEncodedMethod.EMPTY_ARRAY,
DexEncodedMethod.EMPTY_ARRAY,
dexItemFactory.getSkipNameValidationForTesting(),
- DexProgramClass::checksumFromType,
+ clazz.getChecksumSupplier(),
fixupSynthesizedFrom(clazz.getSynthesizedFrom()));
newClass.setInstanceFields(fixupFields(clazz.instanceFields()));
newClass.setStaticFields(fixupFields(clazz.staticFields()));
diff --git a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
index 91484f7..9d5cec5 100644
--- a/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
+++ b/src/main/java/com/android/tools/r8/repackaging/RepackagingUseRegistry.java
@@ -25,12 +25,14 @@
import com.android.tools.r8.graph.SuccessfulMemberResolutionResult;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.InternalOptions;
import java.util.function.Consumer;
import java.util.function.Predicate;
public class RepackagingUseRegistry extends UseRegistry {
private final AppInfoWithLiveness appInfo;
+ private final InternalOptions options;
private final RepackagingConstraintGraph constraintGraph;
private final ProgramDefinition context;
private final InitClassLens initClassLens;
@@ -42,6 +44,7 @@
ProgramDefinition context) {
super(appView.dexItemFactory());
this.appInfo = appView.appInfo();
+ this.options = appView.options();
this.constraintGraph = constraintGraph;
this.context = context;
this.initClassLens = appView.initClassLens();
@@ -60,31 +63,51 @@
return false;
}
- private boolean isOnlyAccessibleFromSamePackage(DexClassAndMember<?, ?> member) {
- AccessFlags<?> accessFlags = member.getAccessFlags();
+ private boolean isOnlyAccessibleFromSamePackage(
+ SuccessfulMemberResolutionResult<?, ?> resolutionResult, boolean isInvoke) {
+ AccessFlags<?> accessFlags = resolutionResult.getResolutionPair().getAccessFlags();
if (accessFlags.isPackagePrivate()) {
return true;
}
- if (accessFlags.isProtected()
- && !appInfo.isSubtype(context.getContextType(), member.getHolderType())) {
- return true;
+ if (accessFlags.isProtected()) {
+ if (!appInfo.isSubtype(
+ context.getContextType(), resolutionResult.getResolvedHolder().getType())) {
+ return true;
+ }
+ // Check for assignability if we are generating CF:
+ // https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.10.1.8
+ if (isInvoke
+ && options.isGeneratingClassFiles()
+ && !appInfo.isSubtype(
+ resolutionResult.getInitialResolutionHolder().getType(), context.getContextType())) {
+ return true;
+ }
}
return false;
}
public void registerFieldAccess(DexField field) {
- registerMemberAccess(appInfo.resolveField(field));
+ registerMemberAccess(appInfo.resolveField(field), false);
}
public ProgramMethod registerMethodReference(DexMethod method) {
ResolutionResult resolutionResult = appInfo.unsafeResolveMethodDueToDexFormat(method);
- registerMemberAccess(resolutionResult);
+ registerMemberAccess(resolutionResult, false);
return resolutionResult.isSingleResolution()
? resolutionResult.asSingleResolution().getResolvedProgramMethod()
: null;
}
+ private void registerMemberAccessForInvoke(MemberResolutionResult<?, ?> resolutionResult) {
+ registerMemberAccess(resolutionResult, true);
+ }
+
public void registerMemberAccess(MemberResolutionResult<?, ?> resolutionResult) {
+ registerMemberAccess(resolutionResult, false);
+ }
+
+ private void registerMemberAccess(
+ MemberResolutionResult<?, ?> resolutionResult, boolean isInvoke) {
SuccessfulMemberResolutionResult<?, ?> successfulResolutionResult =
resolutionResult.asSuccessfulMemberResolutionResult();
if (successfulResolutionResult == null) {
@@ -96,14 +119,16 @@
}
// Check access to the initial resolution holder.
- registerClassTypeAccess(successfulResolutionResult.getInitialResolutionHolder());
+ DexClass initialResolutionHolder = successfulResolutionResult.getInitialResolutionHolder();
+ registerClassTypeAccess(initialResolutionHolder);
// Similarly, check access to the resolved member.
DexClassAndMember<?, ?> resolutionPair = successfulResolutionResult.getResolutionPair();
if (resolutionPair != null) {
RepackagingConstraintGraph.Node resolvedMemberNode =
constraintGraph.getNode(resolutionPair.getDefinition());
- if (resolvedMemberNode != null && isOnlyAccessibleFromSamePackage(resolutionPair)) {
+ if (resolvedMemberNode != null
+ && isOnlyAccessibleFromSamePackage(successfulResolutionResult, isInvoke)) {
node.addNeighbor(resolvedMemberNode);
}
}
@@ -149,27 +174,27 @@
@Override
public void registerInvokeVirtual(DexMethod invokedMethod) {
- registerMemberAccess(appInfo.resolveMethod(invokedMethod, false));
+ registerMemberAccessForInvoke(appInfo.resolveMethod(invokedMethod, false));
}
@Override
public void registerInvokeDirect(DexMethod invokedMethod) {
- registerMemberAccess(appInfo.unsafeResolveMethodDueToDexFormat(invokedMethod));
+ registerMemberAccessForInvoke(appInfo.unsafeResolveMethodDueToDexFormat(invokedMethod));
}
@Override
public void registerInvokeStatic(DexMethod invokedMethod) {
- registerMemberAccess(appInfo.unsafeResolveMethodDueToDexFormat(invokedMethod));
+ registerMemberAccessForInvoke(appInfo.unsafeResolveMethodDueToDexFormat(invokedMethod));
}
@Override
public void registerInvokeInterface(DexMethod invokedMethod) {
- registerMemberAccess(appInfo.resolveMethod(invokedMethod, true));
+ registerMemberAccessForInvoke(appInfo.resolveMethod(invokedMethod, true));
}
@Override
public void registerInvokeSuper(DexMethod invokedMethod) {
- registerMemberAccess(appInfo.unsafeResolveMethodDueToDexFormat(invokedMethod));
+ registerMemberAccessForInvoke(appInfo.unsafeResolveMethodDueToDexFormat(invokedMethod));
}
@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 7687ad4..7f93d17 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -25,8 +25,6 @@
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
import com.android.tools.r8.graph.FieldAccessInfo;
import com.android.tools.r8.graph.FieldAccessInfoCollection;
import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl;
@@ -40,6 +38,7 @@
import com.android.tools.r8.graph.ObjectAllocationInfoCollectionImpl;
import com.android.tools.r8.graph.ProgramField;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
@@ -181,8 +180,6 @@
final Set<DexType> prunedTypes;
/** A map from switchmap class types to their corresponding switchmaps. */
final Map<DexField, Int2ReferenceMap<DexField>> switchMaps;
- /** A map from enum types to their value types and ordinals. */
- final EnumValueInfoMapCollection enumValueInfoMaps;
/* A cache to improve the lookup performance of lookupSingleVirtualTarget */
private final SingleTargetLookupCache singleTargetLookupCache = new SingleTargetLookupCache();
@@ -227,7 +224,6 @@
Object2BooleanMap<DexReference> identifierNameStrings,
Set<DexType> prunedTypes,
Map<DexField, Int2ReferenceMap<DexField>> switchMaps,
- EnumValueInfoMapCollection enumValueInfoMaps,
Set<DexType> lockCandidates,
Map<DexType, Visibility> initClassReferences) {
super(syntheticItems, classToFeatureSplitMap, mainDexClasses);
@@ -266,9 +262,9 @@
this.identifierNameStrings = identifierNameStrings;
this.prunedTypes = prunedTypes;
this.switchMaps = switchMaps;
- this.enumValueInfoMaps = enumValueInfoMaps;
this.lockCandidates = lockCandidates;
this.initClassReferences = initClassReferences;
+ verify();
}
private AppInfoWithLiveness(
@@ -313,25 +309,20 @@
previous.identifierNameStrings,
previous.prunedTypes,
previous.switchMaps,
- previous.enumValueInfoMaps,
previous.lockCandidates,
previous.initClassReferences);
}
- private AppInfoWithLiveness(
- AppInfoWithLiveness previous,
- DirectMappedDexApplication application,
- Set<DexType> removedClasses,
- Collection<? extends DexReference> additionalPinnedItems) {
+ private AppInfoWithLiveness(AppInfoWithLiveness previous, PrunedItems prunedItems) {
this(
- previous.getSyntheticItems().commitPrunedClasses(application, removedClasses),
- previous.getClassToFeatureSplitMap().withoutPrunedClasses(removedClasses),
- previous.getMainDexClasses().withoutPrunedClasses(removedClasses),
+ previous.getSyntheticItems().commitPrunedItems(prunedItems),
+ previous.getClassToFeatureSplitMap().withoutPrunedItems(prunedItems),
+ previous.getMainDexClasses().withoutPrunedItems(prunedItems),
previous.deadProtoTypes,
previous.missingTypes,
- removedClasses == null
- ? previous.liveTypes
- : Sets.difference(previous.liveTypes, removedClasses),
+ prunedItems.hasRemovedClasses()
+ ? Sets.difference(previous.liveTypes, prunedItems.getRemovedClasses())
+ : previous.liveTypes,
previous.targetedMethods,
previous.failedResolutionTargets,
previous.bootstrapMethods,
@@ -342,7 +333,7 @@
previous.methodAccessInfoCollection,
previous.objectAllocationInfoCollection,
previous.callSites,
- extendPinnedItems(previous, additionalPinnedItems),
+ extendPinnedItems(previous, prunedItems.getAdditionalPinnedItems()),
previous.mayHaveSideEffects,
previous.noSideEffects,
previous.assumedValues,
@@ -362,14 +353,17 @@
previous.noStaticClassMerging,
previous.neverPropagateValue,
previous.identifierNameStrings,
- removedClasses == null
- ? previous.prunedTypes
- : CollectionUtils.mergeSets(previous.prunedTypes, removedClasses),
+ prunedItems.hasRemovedClasses()
+ ? CollectionUtils.mergeSets(previous.prunedTypes, prunedItems.getRemovedClasses())
+ : previous.prunedTypes,
previous.switchMaps,
- previous.enumValueInfoMaps,
previous.lockCandidates,
previous.initClassReferences);
- assert keepInfo.verifyNoneArePinned(removedClasses, previous);
+ }
+
+ private void verify() {
+ assert keepInfo.verifyPinnedTypesAreLive(liveTypes);
+ assert objectAllocationInfoCollection.verifyAllocatedTypesAreLive(liveTypes, this);
}
private static KeepInfoCollection extendPinnedItems(
@@ -410,9 +404,7 @@
}
public AppInfoWithLiveness(
- AppInfoWithLiveness previous,
- Map<DexField, Int2ReferenceMap<DexField>> switchMaps,
- EnumValueInfoMapCollection enumValueInfoMaps) {
+ AppInfoWithLiveness previous, Map<DexField, Int2ReferenceMap<DexField>> switchMaps) {
super(
previous.getSyntheticItems().commit(previous.app()),
previous.getClassToFeatureSplitMap(),
@@ -452,10 +444,10 @@
this.identifierNameStrings = previous.identifierNameStrings;
this.prunedTypes = previous.prunedTypes;
this.switchMaps = switchMaps;
- this.enumValueInfoMaps = enumValueInfoMaps;
this.lockCandidates = previous.lockCandidates;
this.initClassReferences = previous.initClassReferences;
previous.markObsolete();
+ verify();
}
public static AppInfoWithLivenessModifier modifier() {
@@ -693,16 +685,6 @@
return missingTypes;
}
- public EnumValueInfoMapCollection getEnumValueInfoMapCollection() {
- assert checkIfObsolete();
- return enumValueInfoMaps;
- }
-
- public EnumValueInfoMap getEnumValueInfoMap(DexType enumType) {
- assert checkIfObsolete();
- return enumValueInfoMaps.getEnumValueInfoMap(enumType);
- }
-
public Int2ReferenceMap<DexField> getSwitchMap(DexField field) {
assert checkIfObsolete();
return switchMaps.get(field);
@@ -803,6 +785,13 @@
if (isPinned(field.field)) {
return false;
}
+ return isFieldOnlyWrittenInMethodIgnoringPinning(field, method);
+ }
+
+ public boolean isFieldOnlyWrittenInMethodIgnoringPinning(
+ DexEncodedField field, DexEncodedMethod method) {
+ assert checkIfObsolete();
+ assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written";
FieldAccessInfo fieldAccessInfo = getFieldAccessInfoCollection().get(field.field);
return fieldAccessInfo != null
&& fieldAccessInfo.isWritten()
@@ -822,7 +811,10 @@
DexType holder = field.getHolderType();
return fieldAccessInfo.isWrittenOnlyInMethodSatisfying(
method ->
- method.getDefinition().isInstanceInitializer() && method.getHolderType() == holder);
+ method.getHolderType() == holder
+ && method
+ .getDefinition()
+ .isOrWillBeInlinedIntoInstanceInitializer(dexItemFactory()));
}
public boolean isStaticFieldWrittenOnlyInEnclosingStaticInitializer(DexEncodedField field) {
@@ -933,17 +925,16 @@
* Returns a copy of this AppInfoWithLiveness where the set of classes is pruned using the given
* DexApplication object.
*/
- public AppInfoWithLiveness prunedCopyFrom(
- DirectMappedDexApplication application,
- Set<DexType> removedClasses,
- Collection<? extends DexReference> additionalPinnedItems) {
+ public AppInfoWithLiveness prunedCopyFrom(PrunedItems prunedItems) {
assert checkIfObsolete();
- if (!removedClasses.isEmpty()) {
+ if (prunedItems.hasRemovedClasses()) {
// Rebuild the hierarchy.
- objectAllocationInfoCollection.mutate(mutator -> {}, this);
- keepInfo.mutate(keepInfo -> keepInfo.removeKeepInfoForPrunedItems(removedClasses));
+ objectAllocationInfoCollection.mutate(
+ mutator -> mutator.removeAllocationsForPrunedItems(prunedItems), this);
+ keepInfo.mutate(
+ keepInfo -> keepInfo.removeKeepInfoForPrunedItems(prunedItems.getRemovedClasses()));
}
- return new AppInfoWithLiveness(this, application, removedClasses, additionalPinnedItems);
+ return new AppInfoWithLiveness(this, prunedItems);
}
public AppInfoWithLiveness rebuildWithLiveness(
@@ -1005,7 +996,6 @@
// Don't rewrite pruned types - the removed types are identified by their original name.
prunedTypes,
lens.rewriteFieldKeys(switchMaps),
- enumValueInfoMaps.rewrittenWithLens(lens),
lens.rewriteTypes(lockCandidates),
lens.rewriteTypeKeys(initClassReferences));
}
@@ -1210,13 +1200,7 @@
public AppInfoWithLiveness withSwitchMaps(Map<DexField, Int2ReferenceMap<DexField>> switchMaps) {
assert checkIfObsolete();
assert this.switchMaps.isEmpty();
- return new AppInfoWithLiveness(this, switchMaps, enumValueInfoMaps);
- }
-
- public AppInfoWithLiveness withEnumValueInfoMaps(EnumValueInfoMapCollection enumValueInfoMaps) {
- assert checkIfObsolete();
- assert this.enumValueInfoMaps.isEmpty();
- return new AppInfoWithLiveness(this, switchMaps, enumValueInfoMaps);
+ return new AppInfoWithLiveness(this, switchMaps);
}
/**
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 f6b5aa2..095ba07 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -47,7 +47,6 @@
import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.DirectMappedDexApplication.Builder;
import com.android.tools.r8.graph.EnclosingMethodAttribute;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl;
import com.android.tools.r8.graph.FieldAccessInfoImpl;
import com.android.tools.r8.graph.FieldResolutionResult;
@@ -115,6 +114,7 @@
import com.android.tools.r8.utils.Visibility;
import com.android.tools.r8.utils.WorkList;
import com.android.tools.r8.utils.collections.ProgramFieldSet;
+import com.android.tools.r8.utils.collections.ProgramMethodMap;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.ImmutableSet;
@@ -364,8 +364,8 @@
private final DesugaredLibraryConversionWrapperAnalysis desugaredLibraryWrapperAnalysis;
private final Map<DexType, Pair<LambdaClass, ProgramMethod>> lambdaClasses =
new IdentityHashMap<>();
- private final Map<DexEncodedMethod, Map<DexCallSite, LambdaClass>> lambdaCallSites =
- new IdentityHashMap<>();
+ private final ProgramMethodMap<Map<DexCallSite, LambdaClass>> lambdaCallSites =
+ ProgramMethodMap.create();
private final Map<DexMethod, ProgramMethod> methodsWithBackports = new IdentityHashMap<>();
private final Set<DexProgramClass> classesWithSerializableLambdas = Sets.newIdentityHashSet();
@@ -821,6 +821,7 @@
// Utility to avoid adding to the worklist if already live.
private boolean enqueueMarkMethodLiveAction(ProgramMethod method, KeepReason reason) {
if (liveMethods.add(method, reason)) {
+ assert !method.getDefinition().getOptimizationInfo().forceInline();
workList.enqueueMarkMethodLiveAction(method, reason);
return true;
}
@@ -929,7 +930,7 @@
LambdaClass lambdaClass = lambdaRewriter.getOrCreateLambdaClass(descriptor, context);
lambdaClasses.put(lambdaClass.type, new Pair<>(lambdaClass, context));
lambdaCallSites
- .computeIfAbsent(contextMethod, k -> new IdentityHashMap<>())
+ .computeIfAbsent(context, k -> new IdentityHashMap<>())
.put(callSite, lambdaClass);
if (lambdaClass.descriptor.interfaces.contains(appView.dexItemFactory().serializableType)) {
classesWithSerializableLambdas.add(context.getHolder());
@@ -3023,6 +3024,9 @@
Map<DexType, Pair<DexProgramClass, ProgramMethod>> syntheticInstantiations =
new IdentityHashMap<>();
+ ProgramMethodMap<Set<DexField>> syntheticStaticFieldReadsByContext =
+ ProgramMethodMap.createLinked();
+
Map<DexMethod, ProgramMethod> liveMethods = new IdentityHashMap<>();
Map<DexType, DexClasspathClass> syntheticClasspathClasses = new IdentityHashMap<>();
@@ -3099,6 +3103,10 @@
InstantiationReason.SYNTHESIZED_CLASS,
fakeReason);
}
+ syntheticStaticFieldReadsByContext.forEach(
+ (context, fields) ->
+ fields.forEach(
+ field -> enqueuer.workList.enqueueTraceStaticFieldRead(field, context)));
for (ProgramMethod liveMethod : liveMethods.values()) {
assert !enqueuer.targetedMethods.contains(liveMethod.getDefinition());
enqueuer.markMethodAsTargeted(liveMethod, fakeReason);
@@ -3106,6 +3114,26 @@
}
enqueuer.liveNonProgramTypes.addAll(syntheticClasspathClasses.values());
}
+
+ void registerStatelessLambdaInstanceFieldReads(
+ ProgramMethodMap<Map<DexCallSite, LambdaClass>> lambdaCallSites) {
+ lambdaCallSites.forEach(this::registerStatelessLambdaInstanceFieldReads);
+ }
+
+ private void registerStatelessLambdaInstanceFieldReads(
+ ProgramMethod context, Map<DexCallSite, LambdaClass> callSites) {
+ Set<DexField> syntheticStaticFieldReadsInContext = null;
+ for (LambdaClass lambdaClass : callSites.values()) {
+ if (lambdaClass.isStateless()) {
+ if (syntheticStaticFieldReadsInContext == null) {
+ syntheticStaticFieldReadsInContext =
+ syntheticStaticFieldReadsByContext.computeIfAbsent(
+ context, ignore -> Sets.newLinkedHashSet());
+ }
+ syntheticStaticFieldReadsInContext.add(lambdaClass.lambdaField);
+ }
+ }
+ }
}
private void synthesize() {
@@ -3179,6 +3207,7 @@
// Rewrite all of the invoke-dynamic instructions to lambda class instantiations.
lambdaCallSites.forEach(this::rewriteLambdaCallSites);
+ additions.registerStatelessLambdaInstanceFieldReads(lambdaCallSites);
// Remove all '$deserializeLambda$' methods which are not supported by desugaring.
for (DexProgramClass clazz : classesWithSerializableLambdas) {
@@ -3307,7 +3336,6 @@
joinIdentifierNameStrings(rootSet.identifierNameStrings, identifierNameStrings),
Collections.emptySet(),
Collections.emptyMap(),
- EnumValueInfoMapCollection.empty(),
lockCandidates,
initClassReferences);
appInfo.markObsolete();
@@ -3441,9 +3469,9 @@
}
private void rewriteLambdaCallSites(
- DexEncodedMethod method, Map<DexCallSite, LambdaClass> callSites) {
+ ProgramMethod context, Map<DexCallSite, LambdaClass> callSites) {
assert !callSites.isEmpty();
- int replaced = LambdaRewriter.desugarLambdas(method, callSites::get);
+ int replaced = LambdaRewriter.desugarLambdas(context, callSites::get);
assert replaced == callSites.size();
}
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
index 85a7b88..da98174 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
@@ -6,7 +6,6 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -23,7 +22,6 @@
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Streams;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@@ -155,14 +153,7 @@
&& getInfo(reference, definitions).isMinificationAllowed(configuration);
}
- public final boolean verifyNoneArePinned(Collection<DexType> types, AppInfo appInfo) {
- for (DexType type : types) {
- DexProgramClass clazz =
- asProgramClassOrNull(appInfo.definitionForWithoutExistenceAssert(type));
- assert clazz == null || !getClassInfo(clazz).isPinned();
- }
- return true;
- }
+ public abstract boolean verifyPinnedTypesAreLive(Set<DexType> liveTypes);
// TODO(b/156715504): We should try to avoid the need for iterating pinned items.
@Deprecated
@@ -446,6 +437,15 @@
}
@Override
+ public boolean verifyPinnedTypesAreLive(Set<DexType> liveTypes) {
+ keepClassInfo.forEach(
+ (type, info) -> {
+ assert !info.isPinned() || liveTypes.contains(type);
+ });
+ return true;
+ }
+
+ @Override
public void forEachPinnedType(Consumer<DexType> consumer) {
keepClassInfo.forEach(
(type, info) -> {
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java b/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java
index a5fbd32..4e6b632 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.PrunedItems;
import com.google.common.collect.Sets;
import java.util.Set;
import java.util.function.Consumer;
@@ -87,10 +88,10 @@
return mainDexClasses.size();
}
- public MainDexClasses withoutPrunedClasses(Set<DexType> prunedClasses) {
+ public MainDexClasses withoutPrunedItems(PrunedItems prunedItems) {
MainDexClasses mainDexClassesAfterPruning = createEmptyMainDexClasses();
for (DexType mainDexClass : mainDexClasses) {
- if (!prunedClasses.contains(mainDexClass)) {
+ if (!prunedItems.getRemovedClasses().contains(mainDexClass)) {
mainDexClassesAfterPruning.mainDexClasses.add(mainDexClass);
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
index 58e85ff..33e64f0 100644
--- a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
@@ -24,10 +24,10 @@
import com.android.tools.r8.utils.SingletonEquivalence;
import com.android.tools.r8.utils.TraversalContinuation;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Multiset.Entry;
@@ -199,8 +199,9 @@
private final Map<MergeKey, Representative> representatives = new HashMap<>();
- private final BiMap<DexField, DexField> fieldMapping = HashBiMap.create();
- private final BidirectionalOneToOneHashMap<DexMethod, DexMethod> methodMapping =
+ private final MutableBidirectionalOneToOneMap<DexField, DexField> newFieldSignatures =
+ new BidirectionalOneToOneHashMap<>();
+ private final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> methodMapping =
new BidirectionalOneToOneHashMap<>();
private int numberOfMergedClasses = 0;
@@ -222,27 +223,18 @@
public NestedGraphLens run() {
appView.appInfo().classesWithDeterministicOrder().forEach(this::merge);
- if (Log.ENABLED) {
- Log.info(
- getClass(),
- "Merged %s classes with %s members.",
- numberOfMergedClasses,
- fieldMapping.size() + methodMapping.size());
- }
appView.setStaticallyMergedClasses(mergedClassesBuilder.build());
return buildGraphLens();
}
private NestedGraphLens buildGraphLens() {
- if (!fieldMapping.isEmpty() || !methodMapping.isEmpty()) {
- BiMap<DexField, DexField> originalFieldSignatures = fieldMapping.inverse();
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> originalMethodSignatures =
+ if (!newFieldSignatures.isEmpty() || !methodMapping.isEmpty()) {
+ BidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures =
methodMapping.getInverseOneToOneMap();
return new NestedGraphLens(
ImmutableMap.of(),
- methodMapping,
- fieldMapping,
- originalFieldSignatures,
+ methodMapping.getForwardMap(),
+ newFieldSignatures,
originalMethodSignatures,
appView.graphLens(),
appView.dexItemFactory());
@@ -501,7 +493,7 @@
DexMethod originalMethod =
methodMapping.getRepresentativeKeyOrDefault(sourceMethod.method, sourceMethod.method);
- methodMapping.forcePut(originalMethod, sourceMethodAfterMove.method);
+ methodMapping.put(originalMethod, sourceMethodAfterMove.method);
existingMethods.add(equivalence.wrap(sourceMethodAfterMove.method));
}
@@ -536,8 +528,8 @@
result[index++] = sourceFieldAfterMove;
DexField originalField =
- fieldMapping.inverse().getOrDefault(sourceField.field, sourceField.field);
- fieldMapping.forcePut(originalField, sourceFieldAfterMove.field);
+ newFieldSignatures.getRepresentativeKeyOrDefault(sourceField.field, sourceField.field);
+ newFieldSignatures.put(originalField, sourceFieldAfterMove.field);
existingFields.add(equivalence.wrap(sourceFieldAfterMove.field));
}
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 434b5d2..6f7d998 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import static com.android.tools.r8.dex.Constants.TEMPORARY_INSTANCE_INITIALIZER_PREFIX;
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.ir.code.Invoke.Type.DIRECT;
import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
@@ -58,7 +59,8 @@
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.Timing;
import com.android.tools.r8.utils.TraversalContinuation;
-import com.android.tools.r8.utils.collections.BidirectionalManyToOneMap;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneHashMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalManyToOneMap;
import com.google.common.base.Equivalence;
import com.google.common.base.Equivalence.Wrapper;
import com.google.common.collect.Iterables;
@@ -206,8 +208,8 @@
private final Set<DexProgramClass> mergeCandidates = new LinkedHashSet<>();
// Map from source class to target class.
- private final BidirectionalManyToOneMap<DexType, DexType> mergedClasses =
- new BidirectionalManyToOneMap<>();
+ private final MutableBidirectionalManyToOneMap<DexType, DexType> mergedClasses =
+ new BidirectionalManyToOneHashMap<>();
// Set of types that must not be merged into their subtype.
private final Set<DexType> pinnedTypes = Sets.newIdentityHashSet();
@@ -901,8 +903,6 @@
private class ClassMerger {
- private static final String CONSTRUCTOR_NAME = "constructor";
-
private final DexProgramClass source;
private final DexProgramClass target;
private final VerticalClassMergerGraphLens.Builder deferredRenamings =
@@ -1365,7 +1365,7 @@
DexMethod newSignature;
int count = 1;
do {
- DexString newName = getFreshName(CONSTRUCTOR_NAME, count, oldHolder);
+ DexString newName = getFreshName(TEMPORARY_INSTANCE_INITIALIZER_PREFIX, count, oldHolder);
newSignature =
application.dexItemFactory.createMethod(target.type, method.method.proto, newName);
count++;
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
index f634f48..008380c 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMergerGraphLens.java
@@ -17,9 +17,10 @@
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.utils.IterableUtils;
+import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
-import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
+import com.android.tools.r8.utils.collections.BidirectionalOneToOneMap;
+import com.android.tools.r8.utils.collections.MutableBidirectionalOneToOneMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import java.util.Collection;
@@ -69,20 +70,18 @@
private VerticalClassMergerGraphLens(
AppView<?> appView,
VerticallyMergedClasses mergedClasses,
- Map<DexField, DexField> fieldMap,
+ BidirectionalManyToOneRepresentativeMap<DexField, DexField> fieldMap,
Map<DexMethod, DexMethod> methodMap,
Set<DexMethod> mergedMethods,
Map<DexType, Map<DexMethod, GraphLensLookupResultProvider>>
contextualVirtualToDirectMethodMaps,
- BiMap<DexField, DexField> originalFieldSignatures,
- BidirectionalOneToOneHashMap<DexMethod, DexMethod> originalMethodSignatures,
+ BidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures,
Map<DexMethod, DexMethod> originalMethodSignaturesForBridges,
GraphLens previousLens) {
super(
mergedClasses.getForwardMap(),
methodMap,
fieldMap,
- originalFieldSignatures,
originalMethodSignatures,
previousLens,
appView.dexItemFactory());
@@ -166,13 +165,14 @@
private final DexItemFactory dexItemFactory;
- protected final BiMap<DexField, DexField> fieldMap = HashBiMap.create();
+ protected final MutableBidirectionalOneToOneMap<DexField, DexField> fieldMap =
+ new BidirectionalOneToOneHashMap<>();
protected final Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>();
private final ImmutableSet.Builder<DexMethod> mergedMethodsBuilder = ImmutableSet.builder();
private final Map<DexType, Map<DexMethod, GraphLensLookupResultProvider>>
contextualVirtualToDirectMethodMaps = new IdentityHashMap<>();
- private final BidirectionalOneToOneHashMap<DexMethod, DexMethod> originalMethodSignatures =
+ private final MutableBidirectionalOneToOneMap<DexMethod, DexMethod> originalMethodSignatures =
new BidirectionalOneToOneHashMap<>();
private final Map<DexMethod, DexMethod> originalMethodSignaturesForBridges =
new IdentityHashMap<>();
@@ -185,11 +185,10 @@
static Builder createBuilderForFixup(Builder builder, VerticallyMergedClasses mergedClasses) {
Builder newBuilder = new Builder(builder.dexItemFactory);
- for (Map.Entry<DexField, DexField> entry : builder.fieldMap.entrySet()) {
- newBuilder.map(
- entry.getKey(),
- builder.getFieldSignatureAfterClassMerging(entry.getValue(), mergedClasses));
- }
+ builder.fieldMap.forEach(
+ (key, value) ->
+ newBuilder.map(
+ key, builder.getFieldSignatureAfterClassMerging(value, mergedClasses)));
for (Map.Entry<DexMethod, DexMethod> entry : builder.methodMap.entrySet()) {
newBuilder.map(
entry.getKey(),
@@ -237,7 +236,6 @@
if (mergedClasses.isEmpty()) {
return null;
}
- BiMap<DexField, DexField> originalFieldSignatures = fieldMap.inverse();
// Build new graph lens.
return new VerticalClassMergerGraphLens(
appView,
@@ -246,7 +244,6 @@
methodMap,
mergedMethodsBuilder.build(),
contextualVirtualToDirectMethodMaps,
- originalFieldSignatures,
originalMethodSignatures,
originalMethodSignaturesForBridges,
appView.graphLens());
@@ -308,7 +305,7 @@
}
public boolean hasOriginalSignatureMappingFor(DexField field) {
- return fieldMap.inverse().containsKey(field);
+ return fieldMap.containsValue(field);
}
public boolean hasOriginalSignatureMappingFor(DexMethod method) {
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
index dcdaafc..bc7d42e 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.graph.GraphLens.NonIdentityGraphLens;
import com.android.tools.r8.graph.ProgramDefinition;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.PrunedItems;
import com.android.tools.r8.ir.conversion.MethodProcessingId;
import com.android.tools.r8.synthesis.SyntheticFinalization.Result;
import com.google.common.collect.ImmutableList;
@@ -223,10 +224,18 @@
return nonLecacySyntheticItems.containsKey(type) || legacySyntheticTypes.contains(type);
}
+ private boolean isLegacyCommittedSynthetic(DexType type) {
+ return legacySyntheticTypes.contains(type);
+ }
+
public boolean isPendingSynthetic(DexType type) {
return pendingDefinitions.containsKey(type) || legacyPendingClasses.containsKey(type);
}
+ public boolean isLegacyPendingSynthetic(DexType type) {
+ return legacyPendingClasses.containsKey(type);
+ }
+
public boolean isSyntheticClass(DexType type) {
return isCommittedSynthetic(type)
|| isPendingSynthetic(type)
@@ -238,6 +247,14 @@
return isSyntheticClass(clazz.type);
}
+ public boolean isLegacySyntheticClass(DexType type) {
+ return isLegacyCommittedSynthetic(type) || isLegacyPendingSynthetic(type);
+ }
+
+ public boolean isLegacySyntheticClass(DexProgramClass clazz) {
+ return isLegacySyntheticClass(clazz.getType());
+ }
+
public Collection<DexProgramClass> getLegacyPendingClasses() {
return Collections.unmodifiableCollection(legacyPendingClasses.values());
}
@@ -301,14 +318,13 @@
// Commit of the synthetic items to a new fully populated application.
public CommittedItems commit(DexApplication application) {
- return commitPrunedClasses(application, Collections.emptySet());
+ return commitPrunedItems(PrunedItems.empty(application));
}
- public CommittedItems commitPrunedClasses(
- DexApplication application, Set<DexType> removedClasses) {
+ public CommittedItems commitPrunedItems(PrunedItems prunedItems) {
return commit(
- application,
- removedClasses,
+ prunedItems.getPrunedApp(),
+ prunedItems.getNoLongerSyntheticItems(),
legacyPendingClasses,
legacySyntheticTypes,
pendingDefinitions,
diff --git a/src/main/java/com/android/tools/r8/tracereferences/MissingDefinitionsDiagnostic.java b/src/main/java/com/android/tools/r8/tracereferences/MissingDefinitionsDiagnostic.java
index 12a2462..1d4e46a 100644
--- a/src/main/java/com/android/tools/r8/tracereferences/MissingDefinitionsDiagnostic.java
+++ b/src/main/java/com/android/tools/r8/tracereferences/MissingDefinitionsDiagnostic.java
@@ -82,12 +82,18 @@
builder.append(" without definition");
builder.append(System.lineSeparator());
builder.append(System.lineSeparator());
- builder.append("Classe(s) without definition:" + System.lineSeparator());
- appendSorted(builder, missingClasses);
- builder.append("Field(s) without definition:" + System.lineSeparator());
- appendSorted(builder, missingFields);
- builder.append("Method(s) without definition:" + System.lineSeparator());
- appendSorted(builder, missingMethods);
+ if (missingClasses.size() > 0) {
+ builder.append("Classe(s) without definition:" + System.lineSeparator());
+ appendSorted(builder, missingClasses);
+ }
+ if (missingFields.size() > 0) {
+ builder.append("Field(s) without definition:" + System.lineSeparator());
+ appendSorted(builder, missingFields);
+ }
+ if (missingMethods.size() > 0) {
+ builder.append("Method(s) without definition:" + System.lineSeparator());
+ appendSorted(builder, missingMethods);
+ }
return builder.toString();
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/CfVersionUtils.java b/src/main/java/com/android/tools/r8/utils/CfVersionUtils.java
new file mode 100644
index 0000000..dadf460
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/CfVersionUtils.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2016, 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.utils;
+
+import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.utils.structural.Ordered;
+import java.util.List;
+
+public class CfVersionUtils {
+
+ public static CfVersion max(List<DexEncodedMethod> methods) {
+ CfVersion result = null;
+ for (DexEncodedMethod method : methods) {
+ if (method.hasClassFileVersion()) {
+ result = Ordered.maxIgnoreNull(result, method.getClassFileVersion());
+ }
+ }
+ return result;
+ }
+}
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 cd3a2db..175a39e 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -21,6 +21,7 @@
import com.android.tools.r8.dex.Marker.Backend;
import com.android.tools.r8.dex.Marker.Tool;
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;
@@ -38,7 +39,6 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.classmerging.HorizontallyMergedLambdaClasses;
import com.android.tools.r8.graph.classmerging.StaticallyMergedClasses;
@@ -49,6 +49,7 @@
import com.android.tools.r8.ir.conversion.MethodProcessingId;
import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
import com.android.tools.r8.ir.optimize.Inliner;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
import com.android.tools.r8.ir.optimize.lambda.kotlin.KotlinLambdaGroupIdFactory;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
@@ -108,11 +109,13 @@
ON
}
- public static final CfVersion SUPPORTED_CF_VERSION = CfVersion.V11;
+ public static final CfVersion SUPPORTED_CF_VERSION = CfVersion.V15;
+ public static final CfVersion EXPERIMENTAL_CF_VERSION = CfVersion.V12;
+
public static final int SUPPORTED_DEX_VERSION =
AndroidApiLevel.LATEST.getDexVersion().getIntValue();
- public static final int ASM_VERSION = Opcodes.ASM7;
+ public static final int ASM_VERSION = Opcodes.ASM9;
public final DexItemFactory itemFactory;
@@ -202,7 +205,7 @@
enableClassStaticizer = false;
enableDevirtualization = false;
enableLambdaMerging = false;
- enableHorizontalClassMerging = false;
+ horizontalClassMergerOptions.disable();
enableStaticClassMerging = false;
enableVerticalClassMerging = false;
enableEnumUnboxing = false;
@@ -238,11 +241,6 @@
public boolean enableFieldBitAccessAnalysis =
System.getProperty("com.android.tools.r8.fieldBitAccessAnalysis") != null;
public boolean enableStaticClassMerging = true;
- public boolean enableHorizontalClassMerging = true;
- public boolean enableHorizontalClassMergingConstructorMerging = true;
- public int horizontalClassMergingMaxGroupSize = 30;
- public int horizontalClassMergingSyntheticArgumentCount = 3;
- public boolean enableHorizontalClassMergingOfKotlinLambdas = true;
public boolean enableVerticalClassMerging = true;
public boolean enableArgumentRemoval = true;
public boolean enableUnusedInterfaceRemoval = true;
@@ -582,7 +580,7 @@
* and check cast instructions needs to be collected.
*/
public boolean isClassMergingExtensionRequired() {
- return enableHorizontalClassMerging || enableVerticalClassMerging;
+ return horizontalClassMergerOptions.isEnabled() || enableVerticalClassMerging;
}
@Override
@@ -615,6 +613,8 @@
private final CallSiteOptimizationOptions callSiteOptimizationOptions =
new CallSiteOptimizationOptions();
+ private final HorizontalClassMergerOptions horizontalClassMergerOptions =
+ new HorizontalClassMergerOptions();
private final ProtoShrinkingOptions protoShrinking = new ProtoShrinkingOptions();
private final KotlinOptimizationOptions kotlinOptimizationOptions =
new KotlinOptimizationOptions();
@@ -638,6 +638,10 @@
return callSiteOptimizationOptions;
}
+ public HorizontalClassMergerOptions horizontalClassMergerOptions() {
+ return horizontalClassMergerOptions;
+ }
+
public ProtoShrinkingOptions protoShrinking() {
return protoShrinking;
}
@@ -1043,6 +1047,23 @@
reporter.warning(new StringDiagnostic(message.toString(), origin));
}
+ 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;
@@ -1243,6 +1264,70 @@
}
}
+ public static class HorizontalClassMergerOptions {
+
+ public boolean enable = true;
+ public boolean enableConstructorMerging = true;
+ public boolean enableJavaLambdaMerging = false;
+ public boolean enableKotlinLambdaMerging = true;
+
+ public int syntheticArgumentCount = 3;
+ public int maxGroupSize = 30;
+
+ public void disable() {
+ enable = false;
+ }
+
+ @Deprecated
+ public void disableKotlinLambdaMerging() {
+ enableKotlinLambdaMerging = false;
+ }
+
+ public void enable() {
+ enable = true;
+ }
+
+ public void enableIf(boolean enable) {
+ this.enable = enable;
+ }
+
+ public void enableJavaLambdaMerging() {
+ enableJavaLambdaMerging = true;
+ }
+
+ public void enableKotlinLambdaMergingIf(boolean enableKotlinLambdaMerging) {
+ this.enableKotlinLambdaMerging = enableKotlinLambdaMerging;
+ }
+
+ public int getMaxGroupSize() {
+ return maxGroupSize;
+ }
+
+ public int getSyntheticArgumentCount() {
+ return syntheticArgumentCount;
+ }
+
+ public boolean isConstructorMergingEnabled() {
+ return enableConstructorMerging;
+ }
+
+ public boolean isDisabled() {
+ return !isEnabled();
+ }
+
+ public boolean isEnabled() {
+ return enable;
+ }
+
+ public boolean isJavaLambdaMergingEnabled() {
+ return enableJavaLambdaMerging;
+ }
+
+ public boolean isKotlinLambdaMergingEnabled() {
+ return enableKotlinLambdaMerging;
+ }
+ }
+
public static class ProtoShrinkingOptions {
public boolean enableGeneratedExtensionRegistryShrinking = false;
@@ -1297,7 +1382,7 @@
public BiConsumer<DexItemFactory, StaticallyMergedClasses> staticallyMergedClassesConsumer =
ConsumerUtils.emptyBiConsumer();
- public BiConsumer<DexItemFactory, EnumValueInfoMapCollection> unboxedEnumsConsumer =
+ public BiConsumer<DexItemFactory, EnumDataMap> unboxedEnumsConsumer =
ConsumerUtils.emptyBiConsumer();
public BiConsumer<DexItemFactory, VerticallyMergedClasses> verticallyMergedClassesConsumer =
@@ -1522,6 +1607,10 @@
return intermediate || hasMinApi(AndroidApiLevel.L);
}
+ public boolean canUseJavaUtilObjects() {
+ return (isGeneratingClassFiles() && !cfToCfDesugar) || hasMinApi(AndroidApiLevel.K);
+ }
+
public boolean canUseRequireNonNull() {
return isGeneratingDex() && hasMinApi(AndroidApiLevel.K);
}
diff --git a/src/main/java/com/android/tools/r8/utils/IterableUtils.java b/src/main/java/com/android/tools/r8/utils/IterableUtils.java
index aee34f6..871a7a5 100644
--- a/src/main/java/com/android/tools/r8/utils/IterableUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/IterableUtils.java
@@ -15,6 +15,10 @@
public class IterableUtils {
+ public static <T> Iterable<T> append(Iterable<T> iterable, T element) {
+ return Iterables.concat(iterable, singleton(element));
+ }
+
public static <T> List<T> ensureUnmodifiableList(Iterable<T> iterable) {
List<T> list;
if (iterable instanceof List<?>) {
diff --git a/src/main/java/com/android/tools/r8/utils/StringUtils.java b/src/main/java/com/android/tools/r8/utils/StringUtils.java
index 902924a..a90d2bc 100644
--- a/src/main/java/com/android/tools/r8/utils/StringUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/StringUtils.java
@@ -341,4 +341,11 @@
throwable.printStackTrace(new PrintWriter(sw));
return sw.toString();
}
+
+ public static String capitalize(String stringToCapitalize) {
+ if (stringToCapitalize == null || stringToCapitalize.isEmpty()) {
+ return stringToCapitalize;
+ }
+ return stringToCapitalize.substring(0, 1).toUpperCase() + stringToCapitalize.substring(1);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToManyMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToManyMap.java
new file mode 100644
index 0000000..09b3c27
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToManyMap.java
@@ -0,0 +1,27 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+/** Interface that accommodates many-to-many mappings. */
+public interface BidirectionalManyToManyMap<K, V> {
+
+ boolean containsKey(K key);
+
+ boolean containsValue(V value);
+
+ void forEach(BiConsumer<? super K, ? super V> consumer);
+
+ void forEachKey(Consumer<? super K> consumer);
+
+ Set<K> getKeys(V value);
+
+ Set<V> getValues(K key);
+
+ boolean isEmpty();
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToManyRepresentativeMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToManyRepresentativeMap.java
index a4878dc..773c066 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToManyRepresentativeMap.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToManyRepresentativeMap.java
@@ -4,91 +4,27 @@
package com.android.tools.r8.utils.collections;
-import java.util.Map;
+/**
+ * Interface that accommodates many-to-many mappings.
+ *
+ * <p>This interface additionally adds a "representative" for each one-to-many/many-to-one mapping.
+ * The representative for a given key is a value from {@link #getValues(K)}. The representative for
+ * a given value is a key from {@link #getKeys(V)}.
+ */
+public interface BidirectionalManyToManyRepresentativeMap<K, V>
+ extends BidirectionalManyToManyMap<K, V> {
-public abstract class BidirectionalManyToManyRepresentativeMap<K, V> {
+ K getRepresentativeKey(V value);
- public static <K, V> BidirectionalManyToManyRepresentativeMap<K, V> empty() {
- return new EmptyBidirectionalManyToManyRepresentativeMap<>();
- }
-
- public abstract boolean containsKey(K key);
-
- public abstract boolean containsValue(V value);
-
- public abstract Map<K, V> getForwardBacking();
-
- public abstract Map<V, K> getInverseBacking();
-
- public final Inverse getInverseManyToManyMap() {
- return new Inverse();
- }
-
- public abstract K getRepresentativeKey(V value);
-
- public final K getRepresentativeKeyOrDefault(V value, K defaultValue) {
+ default K getRepresentativeKeyOrDefault(V value, K defaultValue) {
K representativeKey = getRepresentativeKey(value);
return representativeKey != null ? representativeKey : defaultValue;
}
- public abstract V getRepresentativeValue(K key);
+ V getRepresentativeValue(K key);
- public final V getRepresentativeValueOrDefault(K key, V defaultValue) {
+ default V getRepresentativeValueOrDefault(K key, V defaultValue) {
V representativeValue = getRepresentativeValue(key);
return representativeValue != null ? representativeValue : defaultValue;
}
-
- public abstract Iterable<K> getKeys(V value);
-
- public abstract Iterable<V> getValues(K key);
-
- public abstract boolean isEmpty();
-
- public class Inverse extends BidirectionalManyToManyRepresentativeMap<V, K> {
-
- @Override
- public boolean containsKey(V key) {
- return BidirectionalManyToManyRepresentativeMap.this.containsValue(key);
- }
-
- @Override
- public boolean containsValue(K value) {
- return BidirectionalManyToManyRepresentativeMap.this.containsKey(value);
- }
-
- @Override
- public Map<V, K> getForwardBacking() {
- return BidirectionalManyToManyRepresentativeMap.this.getInverseBacking();
- }
-
- @Override
- public Map<K, V> getInverseBacking() {
- return BidirectionalManyToManyRepresentativeMap.this.getForwardBacking();
- }
-
- @Override
- public V getRepresentativeKey(K value) {
- return BidirectionalManyToManyRepresentativeMap.this.getRepresentativeValue(value);
- }
-
- @Override
- public K getRepresentativeValue(V key) {
- return BidirectionalManyToManyRepresentativeMap.this.getRepresentativeKey(key);
- }
-
- @Override
- public Iterable<V> getKeys(K value) {
- return BidirectionalManyToManyRepresentativeMap.this.getValues(value);
- }
-
- @Override
- public Iterable<K> getValues(V key) {
- return BidirectionalManyToManyRepresentativeMap.this.getKeys(key);
- }
-
- @Override
- public boolean isEmpty() {
- return BidirectionalManyToManyRepresentativeMap.this.isEmpty();
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneHashMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneHashMap.java
new file mode 100644
index 0000000..c217e91
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneHashMap.java
@@ -0,0 +1,143 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+public class BidirectionalManyToOneHashMap<K, V> implements MutableBidirectionalManyToOneMap<K, V> {
+
+ private final Map<K, V> backing;
+ private final Map<V, Set<K>> inverse;
+
+ public BidirectionalManyToOneHashMap() {
+ this(new IdentityHashMap<>(), new IdentityHashMap<>());
+ }
+
+ private BidirectionalManyToOneHashMap(Map<K, V> backing, Map<V, Set<K>> inverse) {
+ this.backing = backing;
+ this.inverse = inverse;
+ }
+
+ @Override
+ public void clear() {
+ backing.clear();
+ inverse.clear();
+ }
+
+ @Override
+ public boolean containsKey(K key) {
+ return backing.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(V value) {
+ return inverse.containsKey(value);
+ }
+
+ @Override
+ public void forEach(BiConsumer<? super K, ? super V> consumer) {
+ backing.forEach(consumer);
+ }
+
+ @Override
+ public void forEachKey(Consumer<? super K> consumer) {
+ backing.keySet().forEach(consumer);
+ }
+
+ @Override
+ public void forEachManyToOneMapping(BiConsumer<? super Set<K>, V> consumer) {
+ inverse.forEach((value, keys) -> consumer.accept(keys, value));
+ }
+
+ @Override
+ public V get(Object key) {
+ return backing.get(key);
+ }
+
+ @Override
+ public V getOrDefault(Object key, V value) {
+ return backing.getOrDefault(key, value);
+ }
+
+ @Override
+ public Map<K, V> getForwardMap() {
+ return backing;
+ }
+
+ @Override
+ public Set<K> keySet() {
+ return backing.keySet();
+ }
+
+ @Override
+ public Set<K> getKeys(V value) {
+ return inverse.getOrDefault(value, Collections.emptySet());
+ }
+
+ @Override
+ public Set<V> getValues(K key) {
+ V value = get(key);
+ return value != null ? Collections.singleton(value) : Collections.emptySet();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return backing.isEmpty();
+ }
+
+ @Override
+ public V remove(K key) {
+ V value = backing.remove(key);
+ if (value != null) {
+ Set<K> keys = inverse.get(value);
+ keys.remove(key);
+ if (keys.isEmpty()) {
+ inverse.remove(value);
+ }
+ }
+ return value;
+ }
+
+ @Override
+ public void removeAll(Iterable<K> keys) {
+ keys.forEach(this::remove);
+ }
+
+ @Override
+ public Set<K> removeValue(V value) {
+ Set<K> keys = inverse.remove(value);
+ if (keys == null) {
+ return Collections.emptySet();
+ }
+ for (K key : keys) {
+ V removedValue = backing.remove(key);
+ assert removedValue == value;
+ }
+ return keys;
+ }
+
+ @Override
+ public void put(K key, V value) {
+ remove(key);
+ backing.put(key, value);
+ inverse.computeIfAbsent(value, ignore -> new LinkedHashSet<>()).add(key);
+ }
+
+ @Override
+ public void put(Iterable<K> keys, V value) {
+ keys.forEach(key -> put(key, value));
+ }
+
+ @Override
+ public Set<V> values() {
+ return inverse.keySet();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneMap.java
index 361b761..1404c6a 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneMap.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneMap.java
@@ -4,109 +4,27 @@
package com.android.tools.r8.utils.collections;
-import java.util.Collections;
-import java.util.IdentityHashMap;
-import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;
import java.util.function.BiConsumer;
-public class BidirectionalManyToOneMap<K, V> {
+/**
+ * Interface that accommodates many-to-one mappings.
+ *
+ * <p>This interface inherits from {@link BidirectionalManyToManyMap} to allow implementing
+ * many-to-many mappings using many-to-one mappings.
+ */
+public interface BidirectionalManyToOneMap<K, V> extends BidirectionalManyToManyMap<K, V> {
- private final Map<K, V> backing;
- private final Map<V, Set<K>> inverse;
+ void forEachManyToOneMapping(BiConsumer<? super Set<K>, V> consumer);
- public BidirectionalManyToOneMap() {
- this(new IdentityHashMap<>(), new IdentityHashMap<>());
- }
+ V get(Object key);
- private BidirectionalManyToOneMap(Map<K, V> backing, Map<V, Set<K>> inverse) {
- this.backing = backing;
- this.inverse = inverse;
- }
+ V getOrDefault(Object key, V defaultValue);
- public static <K, V> BidirectionalManyToOneMap<K, V> empty() {
- return new BidirectionalManyToOneMap<>(Collections.emptyMap(), Collections.emptyMap());
- }
+ Map<K, V> getForwardMap();
- public boolean containsKey(K key) {
- return backing.containsKey(key);
- }
+ Set<K> keySet();
- public boolean containsValue(V value) {
- return inverse.containsKey(value);
- }
-
- public void forEach(BiConsumer<Set<K>, V> consumer) {
- inverse.forEach((value, keys) -> consumer.accept(keys, value));
- }
-
- public V get(K key) {
- return backing.get(key);
- }
-
- public V getOrDefault(K key, V value) {
- return backing.getOrDefault(key, value);
- }
-
- public Map<K, V> getForwardMap() {
- return backing;
- }
-
- public Set<K> keySet() {
- return backing.keySet();
- }
-
- public boolean hasKey(K key) {
- return backing.containsKey(key);
- }
-
- public boolean hasValue(V value) {
- return inverse.containsKey(value);
- }
-
- public Set<K> getKeys(V value) {
- return inverse.getOrDefault(value, Collections.emptySet());
- }
-
- public Set<K> getKeysOrNull(V value) {
- return inverse.get(value);
- }
-
- public boolean isEmpty() {
- return backing.isEmpty();
- }
-
- public void remove(K key) {
- V value = backing.remove(key);
- if (value != null) {
- Set<K> keys = inverse.get(value);
- keys.remove(key);
- if (keys.isEmpty()) {
- inverse.remove(value);
- }
- }
- }
-
- public Set<K> removeValue(V value) {
- Set<K> keys = inverse.remove(value);
- if (keys == null) {
- return Collections.emptySet();
- }
- for (K key : keys) {
- V removedValue = backing.remove(key);
- assert removedValue == value;
- }
- return keys;
- }
-
- public void put(K key, V value) {
- remove(key);
- backing.put(key, value);
- inverse.computeIfAbsent(value, ignore -> new LinkedHashSet<>()).add(key);
- }
-
- public Set<V> values() {
- return inverse.keySet();
- }
+ Set<V> values();
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeHashMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeHashMap.java
new file mode 100644
index 0000000..15e1bec
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeHashMap.java
@@ -0,0 +1,55 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class BidirectionalManyToOneRepresentativeHashMap<K, V>
+ extends BidirectionalManyToOneHashMap<K, V>
+ implements MutableBidirectionalManyToOneRepresentativeMap<K, V> {
+
+ private final Map<V, K> representatives = new IdentityHashMap<>();
+
+ @Override
+ public void clear() {
+ super.clear();
+ representatives.clear();
+ }
+
+ @Override
+ public K removeRepresentativeFor(V value) {
+ return representatives.remove(value);
+ }
+
+ @Override
+ public void setRepresentative(V value, K representative) {
+ representatives.put(value, representative);
+ }
+
+ @Override
+ public K getRepresentativeKey(V value) {
+ Set<K> keys = getKeys(value);
+ if (!keys.isEmpty()) {
+ return keys.size() == 1 ? keys.iterator().next() : representatives.get(value);
+ }
+ return null;
+ }
+
+ @Override
+ public V getRepresentativeValue(K key) {
+ return get(key);
+ }
+
+ @Override
+ public Set<V> getValues(K key) {
+ if (containsKey(key)) {
+ return Collections.singleton(get(key));
+ }
+ return Collections.emptySet();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeMap.java
new file mode 100644
index 0000000..3e7bf7b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalManyToOneRepresentativeMap.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+/**
+ * Interface that accommodates many-to-one mappings.
+ *
+ * <p>This interface implicitly adds a "representative" for each many-to-one mapping by inheriting
+ * from {@link BidirectionalManyToManyRepresentativeMap}.
+ */
+public interface BidirectionalManyToOneRepresentativeMap<K, V>
+ extends BidirectionalManyToOneMap<K, V>, BidirectionalManyToManyRepresentativeMap<K, V> {}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyHashMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyHashMap.java
new file mode 100644
index 0000000..552a406
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyHashMap.java
@@ -0,0 +1,137 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+public class BidirectionalOneToManyHashMap<K, V> implements MutableBidirectionalOneToManyMap<K, V> {
+
+ private final Map<K, Set<V>> backing;
+ private final Map<V, K> inverse;
+
+ public BidirectionalOneToManyHashMap() {
+ this(new IdentityHashMap<>(), new IdentityHashMap<>());
+ }
+
+ private BidirectionalOneToManyHashMap(Map<K, Set<V>> backing, Map<V, K> inverse) {
+ this.backing = backing;
+ this.inverse = inverse;
+ }
+
+ @Override
+ public void clear() {
+ backing.clear();
+ inverse.clear();
+ }
+
+ @Override
+ public boolean containsKey(K key) {
+ return backing.containsKey(key);
+ }
+
+ @Override
+ public boolean containsValue(V value) {
+ return inverse.containsKey(value);
+ }
+
+ @Override
+ public void forEach(BiConsumer<? super K, ? super V> consumer) {
+ backing.forEach((key, values) -> values.forEach(value -> consumer.accept(key, value)));
+ }
+
+ @Override
+ public void forEachKey(Consumer<? super K> consumer) {
+ backing.keySet().forEach(consumer);
+ }
+
+ @Override
+ public void forEachOneToManyMapping(BiConsumer<K, Set<V>> consumer) {
+ backing.forEach(consumer);
+ }
+
+ @Override
+ public Set<V> get(Object key) {
+ return backing.get(key);
+ }
+
+ @Override
+ public Set<V> getOrDefault(Object key, Set<V> value) {
+ return backing.getOrDefault(key, value);
+ }
+
+ @Override
+ public K getKey(V value) {
+ return inverse.get(value);
+ }
+
+ @Override
+ public Set<K> getKeys(V value) {
+ K key = inverse.get(value);
+ return key != null ? Collections.singleton(key) : Collections.emptySet();
+ }
+
+ @Override
+ public Set<V> getValues(K key) {
+ return getOrDefault(key, Collections.emptySet());
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return backing.isEmpty();
+ }
+
+ public Set<K> keySet() {
+ return backing.keySet();
+ }
+
+ @Override
+ public Set<V> remove(K key) {
+ Set<V> values = backing.remove(key);
+ if (values == null) {
+ return Collections.emptySet();
+ }
+ for (V value : values) {
+ K removedKey = inverse.remove(value);
+ assert removedKey == key;
+ }
+ return values;
+ }
+
+ @Override
+ public void removeAll(Iterable<K> keys) {
+ keys.forEach(this::remove);
+ }
+
+ @Override
+ public K removeValue(V value) {
+ K key = inverse.remove(value);
+ if (key != null) {
+ Set<V> values = backing.get(key);
+ values.remove(value);
+ if (values.isEmpty()) {
+ backing.remove(key);
+ }
+ }
+ return key;
+ }
+
+ @Override
+ public void put(K key, V value) {
+ removeValue(value);
+ backing.computeIfAbsent(key, ignore -> new LinkedHashSet<>()).add(value);
+ inverse.put(value, key);
+ }
+
+ @Override
+ public void put(K key, Set<V> values) {
+ values.forEach(value -> put(key, value));
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyMap.java
new file mode 100644
index 0000000..addb1ed
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyMap.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import java.util.Set;
+import java.util.function.BiConsumer;
+
+/**
+ * Interface that accommodates many-to-many mappings.
+ *
+ * <p>This interface inherits from {@link BidirectionalManyToManyMap} to allow implementing
+ * many-to-many mappings using many-to-one mappings.
+ */
+public interface BidirectionalOneToManyMap<K, V> extends BidirectionalManyToManyMap<K, V> {
+
+ void forEachOneToManyMapping(BiConsumer<K, Set<V>> consumer);
+
+ Set<V> get(Object key);
+
+ Set<V> getOrDefault(Object key, Set<V> defaultValue);
+
+ K getKey(V value);
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyRepresentativeHashMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyRepresentativeHashMap.java
new file mode 100644
index 0000000..93562e7
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyRepresentativeHashMap.java
@@ -0,0 +1,71 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import com.google.common.collect.Streams;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class BidirectionalOneToManyRepresentativeHashMap<K, V>
+ extends BidirectionalOneToManyHashMap<K, V>
+ implements MutableBidirectionalOneToManyRepresentativeMap<K, V> {
+
+ private final Map<K, V> representatives = new IdentityHashMap<>();
+
+ @Override
+ public void clear() {
+ super.clear();
+ representatives.clear();
+ }
+
+ @Override
+ public K getRepresentativeKey(V value) {
+ return getKey(value);
+ }
+
+ @Override
+ public V getRepresentativeValue(K key) {
+ Set<V> values = getValues(key);
+ if (!values.isEmpty()) {
+ return values.size() == 1 ? values.iterator().next() : representatives.get(key);
+ }
+ return null;
+ }
+
+ @Override
+ public Set<V> remove(K key) {
+ Set<V> values = super.remove(key);
+ removeRepresentativeFor(key);
+ return values;
+ }
+
+ @Override
+ public void removeAll(Iterable<K> keys) {
+ super.removeAll(keys);
+ assert Streams.stream(keys).noneMatch(representatives::containsKey);
+ }
+
+ @Override
+ public V removeRepresentativeFor(K key) {
+ return representatives.remove(key);
+ }
+
+ @Override
+ public K removeValue(V value) {
+ K key = super.removeValue(value);
+ if (getValues(key).size() <= 1 || getRepresentativeValue(key) == value) {
+ removeRepresentativeFor(key);
+ }
+ return key;
+ }
+
+ @Override
+ public void setRepresentative(K key, V representative) {
+ assert getValues(key).size() > 1;
+ assert getValues(key).contains(representative);
+ representatives.put(key, representative);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyRepresentativeMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyRepresentativeMap.java
new file mode 100644
index 0000000..557173c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToManyRepresentativeMap.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+/**
+ * Interface that accommodates one-to-many mappings.
+ *
+ * <p>This interface implicitly adds a "representative" for each many-to-one mapping by inheriting
+ * from {@link BidirectionalManyToManyRepresentativeMap}.
+ */
+public interface BidirectionalOneToManyRepresentativeMap<K, V>
+ extends BidirectionalOneToManyMap<K, V>, BidirectionalManyToManyRepresentativeMap<K, V> {}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToOneHashMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToOneHashMap.java
index d618b52..8e2edb5 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToOneHashMap.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToOneHashMap.java
@@ -4,15 +4,16 @@
package com.android.tools.r8.utils.collections;
-import com.android.tools.r8.utils.IterableUtils;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
-import java.util.Collection;
+import java.util.Collections;
import java.util.Map;
import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
public class BidirectionalOneToOneHashMap<K, V>
- extends BidirectionalManyToManyRepresentativeMap<K, V> implements Map<K, V> {
+ implements MutableBidirectionalOneToOneMap<K, V>, Map<K, V> {
private final BiMap<K, V> backing;
@@ -44,8 +45,19 @@
return backing.entrySet();
}
- public V forcePut(K key, V value) {
- return backing.forcePut(key, value);
+ @Override
+ public void forEach(BiConsumer<? super K, ? super V> consumer) {
+ backing.forEach(consumer);
+ }
+
+ @Override
+ public void forEachKey(Consumer<? super K> consumer) {
+ backing.keySet().forEach(consumer);
+ }
+
+ @Override
+ public void forEachManyToOneMapping(BiConsumer<? super Set<K>, V> consumer) {
+ backing.forEach((key, value) -> consumer.accept(Collections.singleton(key), value));
}
@Override
@@ -54,15 +66,17 @@
}
@Override
- public BiMap<K, V> getForwardBacking() {
+ public V getOrDefault(Object key, V defaultValue) {
+ V value = get(key);
+ return value != null ? value : defaultValue;
+ }
+
+ @Override
+ public BiMap<K, V> getForwardMap() {
return backing;
}
@Override
- public BiMap<V, K> getInverseBacking() {
- return backing.inverse();
- }
-
public BidirectionalOneToOneHashMap<V, K> getInverseOneToOneMap() {
return new BidirectionalOneToOneHashMap<>(backing.inverse());
}
@@ -78,19 +92,19 @@
}
@Override
- public Iterable<K> getKeys(V value) {
+ public Set<K> getKeys(V value) {
if (containsValue(value)) {
- return IterableUtils.singleton(getRepresentativeKey(value));
+ return Collections.singleton(getRepresentativeKey(value));
}
- return IterableUtils.empty();
+ return Collections.emptySet();
}
@Override
- public Iterable<V> getValues(K key) {
+ public Set<V> getValues(K key) {
if (containsKey(key)) {
- return IterableUtils.singleton(getRepresentativeValue(key));
+ return Collections.singleton(getRepresentativeValue(key));
}
- return IterableUtils.empty();
+ return Collections.emptySet();
}
@Override
@@ -105,11 +119,12 @@
@Override
public V put(K key, V value) {
- return backing.put(key, value);
+ return backing.forcePut(key, value);
}
- public void putAll(BidirectionalOneToOneHashMap<K, V> map) {
- putAll(map.backing);
+ @Override
+ public void putAll(BidirectionalManyToManyMap<K, V> map) {
+ map.forEach(this::put);
}
@Override
@@ -128,7 +143,7 @@
}
@Override
- public Collection<V> values() {
+ public Set<V> values() {
return backing.values();
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToOneMap.java b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToOneMap.java
new file mode 100644
index 0000000..e5085c2
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/BidirectionalOneToOneMap.java
@@ -0,0 +1,22 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import com.google.common.collect.BiMap;
+
+/**
+ * Interface that accommodates one-to-one mappings.
+ *
+ * <p>This interface inherits from {@link BidirectionalManyToManyRepresentativeMap} to allow
+ * implementing many-to-many mappings using one-to-one mappings.
+ */
+public interface BidirectionalOneToOneMap<K, V>
+ extends BidirectionalManyToOneRepresentativeMap<K, V> {
+
+ @Override
+ BiMap<K, V> getForwardMap();
+
+ BidirectionalOneToOneMap<V, K> getInverseOneToOneMap();
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/EmptyBidirectionalManyToManyRepresentativeMap.java b/src/main/java/com/android/tools/r8/utils/collections/EmptyBidirectionalManyToManyRepresentativeMap.java
deleted file mode 100644
index dbcb753..0000000
--- a/src/main/java/com/android/tools/r8/utils/collections/EmptyBidirectionalManyToManyRepresentativeMap.java
+++ /dev/null
@@ -1,58 +0,0 @@
-// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-package com.android.tools.r8.utils.collections;
-
-import com.android.tools.r8.utils.IterableUtils;
-import java.util.Collections;
-import java.util.Map;
-
-public class EmptyBidirectionalManyToManyRepresentativeMap<K, V>
- extends BidirectionalManyToManyRepresentativeMap<K, V> {
-
- @Override
- public boolean containsKey(K key) {
- return false;
- }
-
- @Override
- public boolean containsValue(V value) {
- return false;
- }
-
- @Override
- public Map<K, V> getForwardBacking() {
- return Collections.emptyMap();
- }
-
- @Override
- public Map<V, K> getInverseBacking() {
- return Collections.emptyMap();
- }
-
- @Override
- public K getRepresentativeKey(V value) {
- return null;
- }
-
- @Override
- public V getRepresentativeValue(K key) {
- return null;
- }
-
- @Override
- public Iterable<K> getKeys(V value) {
- return IterableUtils.empty();
- }
-
- @Override
- public Iterable<V> getValues(K key) {
- return IterableUtils.empty();
- }
-
- @Override
- public boolean isEmpty() {
- return true;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/EmptyBidirectionalOneToOneMap.java b/src/main/java/com/android/tools/r8/utils/collections/EmptyBidirectionalOneToOneMap.java
new file mode 100644
index 0000000..f2c10c3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/EmptyBidirectionalOneToOneMap.java
@@ -0,0 +1,98 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import com.google.common.collect.BiMap;
+import com.google.common.collect.HashBiMap;
+import java.util.Collections;
+import java.util.Set;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+public class EmptyBidirectionalOneToOneMap<K, V>
+ implements BidirectionalOneToOneMap<K, V>,
+ BidirectionalManyToOneRepresentativeMap<K, V>,
+ BidirectionalManyToManyRepresentativeMap<K, V> {
+
+ @Override
+ public boolean containsKey(K key) {
+ return false;
+ }
+
+ @Override
+ public boolean containsValue(V value) {
+ return false;
+ }
+
+ @Override
+ public void forEach(BiConsumer<? super K, ? super V> consumer) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void forEachKey(Consumer<? super K> consumer) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public void forEachManyToOneMapping(BiConsumer<? super Set<K>, V> consumer) {
+ // Intentionally empty.
+ }
+
+ @Override
+ public V get(Object key) {
+ return null;
+ }
+
+ @Override
+ public V getOrDefault(Object key, V defaultValue) {
+ return defaultValue;
+ }
+
+ @Override
+ public BiMap<K, V> getForwardMap() {
+ return HashBiMap.create();
+ }
+
+ @Override
+ public K getRepresentativeKey(V value) {
+ return null;
+ }
+
+ @Override
+ public V getRepresentativeValue(K key) {
+ return null;
+ }
+
+ @Override
+ public Set<K> getKeys(V value) {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Set<V> getValues(K key) {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return true;
+ }
+
+ @Override
+ public Set<K> keySet() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public Set<V> values() {
+ return Collections.emptySet();
+ }
+
+ @Override
+ public BidirectionalOneToOneMap<V, K> getInverseOneToOneMap() {
+ return new EmptyBidirectionalOneToOneMap<>();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneMap.java b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneMap.java
new file mode 100644
index 0000000..7953e91
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneMap.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import java.util.Set;
+
+/** Interface that provides mutable access to the implementation of a many-to-one mapping. */
+public interface MutableBidirectionalManyToOneMap<K, V> extends BidirectionalManyToOneMap<K, V> {
+
+ void clear();
+
+ void put(K key, V value);
+
+ void put(Iterable<K> key, V value);
+
+ V remove(K key);
+
+ void removeAll(Iterable<K> keys);
+
+ Set<K> removeValue(V value);
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneRepresentativeMap.java b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneRepresentativeMap.java
new file mode 100644
index 0000000..24f91ac
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalManyToOneRepresentativeMap.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+/** Interface that provides mutable access to the implementation of a many-to-one mapping. */
+public interface MutableBidirectionalManyToOneRepresentativeMap<K, V>
+ extends MutableBidirectionalManyToOneMap<K, V>, BidirectionalManyToOneRepresentativeMap<K, V> {
+
+ K removeRepresentativeFor(V value);
+
+ void setRepresentative(V value, K representative);
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToManyMap.java b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToManyMap.java
new file mode 100644
index 0000000..1b9d464
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToManyMap.java
@@ -0,0 +1,23 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import java.util.Set;
+
+/** Interface that provides mutable access to the implementation of a one-to-many mapping. */
+public interface MutableBidirectionalOneToManyMap<K, V> extends BidirectionalOneToManyMap<K, V> {
+
+ void clear();
+
+ Set<V> remove(K key);
+
+ void removeAll(Iterable<K> keys);
+
+ K removeValue(V value);
+
+ void put(K key, V value);
+
+ void put(K key, Set<V> values);
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToManyRepresentativeMap.java b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToManyRepresentativeMap.java
new file mode 100644
index 0000000..987eb6f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToManyRepresentativeMap.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+/** Interface that provides mutable access to the implementation of a one-to-many mapping. */
+public interface MutableBidirectionalOneToManyRepresentativeMap<K, V>
+ extends MutableBidirectionalOneToManyMap<K, V>, BidirectionalOneToManyRepresentativeMap<K, V> {
+
+ V removeRepresentativeFor(K key);
+
+ void setRepresentative(K key, V representative);
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToOneMap.java b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToOneMap.java
new file mode 100644
index 0000000..5e5f469
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/MutableBidirectionalOneToOneMap.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+/** Interface that provides mutable access to the implementation of a one-to-one mapping. */
+public interface MutableBidirectionalOneToOneMap<K, V> extends BidirectionalOneToOneMap<K, V> {
+
+ V put(K key, V value);
+
+ void putAll(BidirectionalManyToManyMap<K, V> map);
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodMap.java b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodMap.java
new file mode 100644
index 0000000..d49928a
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodMap.java
@@ -0,0 +1,57 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.utils.collections;
+
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.utils.ProgramMethodEquivalence;
+import com.google.common.base.Equivalence.Wrapper;
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.Map;
+import java.util.function.BiConsumer;
+import java.util.function.Function;
+import java.util.function.Supplier;
+
+public class ProgramMethodMap<V> {
+
+ private final Map<Wrapper<ProgramMethod>, V> backing;
+
+ private ProgramMethodMap(Supplier<Map<Wrapper<ProgramMethod>, V>> backingFactory) {
+ backing = backingFactory.get();
+ }
+
+ public static <V> ProgramMethodMap<V> create() {
+ return new ProgramMethodMap<>(HashMap::new);
+ }
+
+ public static <V> ProgramMethodMap<V> createLinked() {
+ return new ProgramMethodMap<>(LinkedHashMap::new);
+ }
+
+ public void clear() {
+ backing.clear();
+ }
+
+ public V computeIfAbsent(ProgramMethod method, Function<ProgramMethod, V> fn) {
+ return backing.computeIfAbsent(wrap(method), key -> fn.apply(key.get()));
+ }
+
+ public void forEach(BiConsumer<ProgramMethod, V> consumer) {
+ backing.forEach((wrapper, value) -> consumer.accept(wrapper.get(), value));
+ }
+
+ public boolean isEmpty() {
+ return backing.isEmpty();
+ }
+
+ public V put(ProgramMethod method, V value) {
+ Wrapper<ProgramMethod> wrapper = ProgramMethodEquivalence.get().wrap(method);
+ return backing.put(wrapper, value);
+ }
+
+ private static Wrapper<ProgramMethod> wrap(ProgramMethod method) {
+ return ProgramMethodEquivalence.get().wrap(method);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorBase.java b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorBase.java
index ee264cc..234732c 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorBase.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/CompareToVisitorBase.java
@@ -104,6 +104,11 @@
}
@Override
+ ItemSpecification<T> self() {
+ return this;
+ }
+
+ @Override
public ItemSpecification<T> withAssert(Predicate<T> predicate) {
assert predicate.test(item1);
assert predicate.test(item2);
@@ -159,6 +164,22 @@
}
@Override
+ public ItemSpecification<T> withShortArray(Function<T, short[]> getter) {
+ if (order == 0) {
+ short[] is1 = getter.apply(item1);
+ short[] is2 = getter.apply(item2);
+ int minLength = Math.min(is1.length, is2.length);
+ for (int i = 0; i < minLength && order == 0; i++) {
+ order = parent.visitInt(is1[i], is2[i]);
+ }
+ if (order == 0) {
+ order = parent.visitInt(is1.length, is2.length);
+ }
+ }
+ return this;
+ }
+
+ @Override
public <S> ItemSpecification<T> withConditionalCustomItem(
Predicate<T> predicate,
Function<T, S> getter,
@@ -184,5 +205,13 @@
}
return this;
}
+
+ @Override
+ public ItemSpecification<T> withDexReference(Function<T, DexReference> getter) {
+ if (order == 0) {
+ order = parent.visitDexReference(getter.apply(item1), getter.apply(item2));
+ }
+ return this;
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java b/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java
index c64e0b8..892183d 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/HashCodeVisitor.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils.structural;
+import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.utils.structural.StructuralItem.CompareToAccept;
import com.android.tools.r8.utils.structural.StructuralItem.HashingAccept;
import java.util.Arrays;
@@ -23,6 +24,10 @@
*/
public class HashCodeVisitor<T> extends StructuralSpecification<T, HashCodeVisitor<T>> {
+ public static <T extends StructuralItem<T>> int run(T item) {
+ return run(item, item.getStructuralMapping());
+ }
+
public static <T> int run(T item, StructuralMapping<T> visit) {
HashCodeVisitor<T> visitor = new HashCodeVisitor<>(item);
visit.apply(visitor);
@@ -37,6 +42,11 @@
this.item = item;
}
+ @Override
+ HashCodeVisitor<T> self() {
+ return this;
+ }
+
private HashCodeVisitor<T> amend(int value) {
// This mirrors the behavior of Objects.hash(values...) / Arrays.hashCode(array).
hashCode = 31 * hashCode + value;
@@ -75,6 +85,11 @@
}
@Override
+ public HashCodeVisitor<T> withShortArray(Function<T, short[]> getter) {
+ return amend(Arrays.hashCode(getter.apply(item)));
+ }
+
+ @Override
protected <S> HashCodeVisitor<T> withConditionalCustomItem(
Predicate<T> predicate,
Function<T, S> getter,
@@ -98,4 +113,9 @@
}
return this;
}
+
+ @Override
+ public HashCodeVisitor<T> withDexReference(Function<T, DexReference> getter) {
+ return amend(getter.apply(item).hashCode());
+ }
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java b/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java
index ba499a3..e63ac6c 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/HashingVisitorWithTypeEquivalence.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils.structural;
+import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.utils.structural.StructuralItem.CompareToAccept;
@@ -101,6 +102,11 @@
}
@Override
+ ItemSpecification<T> self() {
+ return this;
+ }
+
+ @Override
public ItemSpecification<T> withAssert(Predicate<T> predicate) {
assert predicate.test(item);
return this;
@@ -140,6 +146,15 @@
}
@Override
+ public ItemSpecification<T> withShortArray(Function<T, short[]> getter) {
+ short[] ints = getter.apply(item);
+ for (int i = 0; i < ints.length; i++) {
+ parent.visitInt(ints[i]);
+ }
+ return this;
+ }
+
+ @Override
protected <S> ItemSpecification<T> withConditionalCustomItem(
Predicate<T> predicate,
Function<T, S> getter,
@@ -160,5 +175,11 @@
parent.visitItemIterator(getter.apply(item), hasher);
return this;
}
+
+ @Override
+ public ItemSpecification<T> withDexReference(Function<T, DexReference> getter) {
+ parent.visitDexReference(getter.apply(item));
+ return this;
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java b/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java
index 891fbd7..a81fc18 100644
--- a/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java
+++ b/src/main/java/com/android/tools/r8/utils/structural/StructuralSpecification.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.utils.structural;
+import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.utils.structural.StructuralItem.CompareToAccept;
import com.android.tools.r8.utils.structural.StructuralItem.HashingAccept;
import java.util.Arrays;
@@ -16,6 +17,14 @@
public abstract class StructuralSpecification<T, V extends StructuralSpecification<T, V>> {
+ abstract V self();
+
+ /** Apply a structural mapping to the present specification. */
+ public final V withSpec(StructuralMapping<T> spec) {
+ spec.apply(this);
+ return self();
+ }
+
/**
* Base for accessing and visiting a sub-part on an item.
*
@@ -85,6 +94,25 @@
StructuralItem::acceptHashing);
}
+ public final <S extends StructuralItem<S>> V withItemArrayAllowingNullMembers(
+ Function<T, S[]> getter) {
+ return withItemIterator(
+ getter.andThen(a -> Arrays.asList(a).iterator()),
+ (a, b, visitor) -> {
+ if (a == null || b == null) {
+ return visitor.visitBool(a != null, b != null);
+ }
+ return a.acceptCompareTo(b, visitor);
+ },
+ (a, visitor) -> {
+ if (a == null) {
+ visitor.visitInt(0);
+ } else {
+ a.acceptHashing(visitor);
+ }
+ });
+ }
+
/**
* Helper to declare an assert on the item.
*
@@ -103,4 +131,8 @@
public abstract V withDouble(ToDoubleFunction<T> getter);
public abstract V withIntArray(Function<T, int[]> getter);
+
+ public abstract V withShortArray(Function<T, short[]> getter);
+
+ public abstract V withDexReference(Function<T, DexReference> getter);
}
diff --git a/src/test/examples/classmerging/ConflictInGeneratedNameTest.java b/src/test/examples/classmerging/ConflictInGeneratedNameTest.java
index 6d566ec..396e73c 100644
--- a/src/test/examples/classmerging/ConflictInGeneratedNameTest.java
+++ b/src/test/examples/classmerging/ConflictInGeneratedNameTest.java
@@ -15,11 +15,11 @@
public A() {
print("In A.<init>()");
- constructor$classmerging$ConflictInGeneratedNameTest$A();
+ $r8$constructor$classmerging$ConflictInGeneratedNameTest$A();
}
- private void constructor$classmerging$ConflictInGeneratedNameTest$A() {
- print("In A.constructor$classmerging$ConflictInGeneratedNameTest$A()");
+ private void $r8$constructor$classmerging$ConflictInGeneratedNameTest$A() {
+ print("In A.$r8$constructor$classmerging$ConflictInGeneratedNameTest$A()");
}
public void printState() {
diff --git a/src/test/examplesAndroidO/lambdadesugaring/LambdaDesugaring.java b/src/test/examplesAndroidO/lambdadesugaring/LambdaDesugaring.java
index b54be6b..627d255 100644
--- a/src/test/examplesAndroidO/lambdadesugaring/LambdaDesugaring.java
+++ b/src/test/examplesAndroidO/lambdadesugaring/LambdaDesugaring.java
@@ -398,7 +398,15 @@
try {
testEnforcedSignatureHelper();
} catch (Exception e) {
- System.out.println(e.getMessage());
+ if (e.getMessage().contains("cannot be cast to lambdadesugaring.LambdaDesugaring$B")
+ || e.getMessage()
+ .contains("cannot be cast to class lambdadesugaring.LambdaDesugaring$B")) {
+ System.out.println(
+ "lambdadesugaring.LambdaDesugaring$A cannot be cast to"
+ + " lambdadesugaring.LambdaDesugaring$B");
+ } else {
+ System.out.println(e.getMessage());
+ }
}
atA(t -> new LambdaDesugaring().reorder(t));
diff --git a/src/test/examplesJava15/records/Main.java b/src/test/examplesJava15/records/Main.java
new file mode 100644
index 0000000..7be696d
--- /dev/null
+++ b/src/test/examplesJava15/records/Main.java
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package records;
+
+public class Main {
+
+ record Person(String name, int age) {}
+
+ public static void main(String[] args) {
+ Person janeDoe = new Person("Jane Doe", 42);
+ System.out.println(janeDoe.name);
+ System.out.println(janeDoe.age);
+ }
+}
diff --git a/src/test/examplesJava15/sealed/Compiler.java b/src/test/examplesJava15/sealed/Compiler.java
new file mode 100644
index 0000000..8d29eea
--- /dev/null
+++ b/src/test/examplesJava15/sealed/Compiler.java
@@ -0,0 +1,10 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package sealed;
+
+public sealed abstract class Compiler permits R8Compiler, D8Compiler {
+
+ public abstract void run();
+}
\ No newline at end of file
diff --git a/src/test/examplesJava15/sealed/D8Compiler.java b/src/test/examplesJava15/sealed/D8Compiler.java
new file mode 100644
index 0000000..e86df73
--- /dev/null
+++ b/src/test/examplesJava15/sealed/D8Compiler.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package sealed;
+
+public final class D8Compiler extends Compiler {
+
+ public void run() {
+ System.out.println("D8 compiler");
+ }
+}
diff --git a/src/test/examplesJava15/sealed/Main.java b/src/test/examplesJava15/sealed/Main.java
new file mode 100644
index 0000000..f163a21
--- /dev/null
+++ b/src/test/examplesJava15/sealed/Main.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package sealed;
+
+public class Main {
+
+ public static void main(String[] args) {
+ new R8Compiler().run();
+ new D8Compiler().run();
+ }
+}
diff --git a/src/test/examplesJava15/sealed/R8Compiler.java b/src/test/examplesJava15/sealed/R8Compiler.java
new file mode 100644
index 0000000..72a522a
--- /dev/null
+++ b/src/test/examplesJava15/sealed/R8Compiler.java
@@ -0,0 +1,12 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package sealed;
+
+public final class R8Compiler extends Compiler {
+
+ public void run() {
+ System.out.println("R8 compiler");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/CfFrontendExamplesTest.java b/src/test/java/com/android/tools/r8/CfFrontendExamplesTest.java
index cea34f9..5bb4d63 100644
--- a/src/test/java/com/android/tools/r8/CfFrontendExamplesTest.java
+++ b/src/test/java/com/android/tools/r8/CfFrontendExamplesTest.java
@@ -21,12 +21,25 @@
import java.util.List;
import java.util.function.BiConsumer;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.util.ASMifier;
import org.objectweb.asm.util.TraceClassVisitor;
+@RunWith(Parameterized.class)
public class CfFrontendExamplesTest extends TestBase {
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public CfFrontendExamplesTest(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
@Test
public void testArithmetic() throws Exception {
runTest("arithmetic.Arithmetic");
diff --git a/src/test/java/com/android/tools/r8/DiagnosticsChecker.java b/src/test/java/com/android/tools/r8/DiagnosticsChecker.java
index bda7fe1..73d1d3a 100644
--- a/src/test/java/com/android/tools/r8/DiagnosticsChecker.java
+++ b/src/test/java/com/android/tools/r8/DiagnosticsChecker.java
@@ -48,10 +48,10 @@
void run(DiagnosticsHandler handler) throws CompilationFailedException;
}
- public static void checkContains(String snippet, List<Diagnostic> diagnostics) {
+ private static void checkContains(String snippet, List<Diagnostic> diagnostics) {
List<String> messages = ListUtils.map(diagnostics, Diagnostic::getDiagnosticMessage);
System.out.println("Expecting match for '" + snippet + "'");
- System.out.println("StdErr:\n" + messages);
+ System.out.println("Diagnostics messages:\n" + messages);
assertTrue(
"Expected to find snippet '"
+ snippet
@@ -60,10 +60,26 @@
diagnostics.stream().anyMatch(d -> d.getDiagnosticMessage().contains(snippet)));
}
+ private static void checkNotContains(String snippet, List<Diagnostic> diagnostics) {
+ List<String> messages = ListUtils.map(diagnostics, Diagnostic::getDiagnosticMessage);
+ System.out.println("Expecting no match for '" + snippet + "'");
+ System.out.println("Diagnostics messages:\n" + messages);
+ assertTrue(
+ "Expected to *not* find snippet '"
+ + snippet
+ + "' in error messages:\n"
+ + String.join("\n", messages),
+ diagnostics.stream().noneMatch(d -> d.getDiagnosticMessage().contains(snippet)));
+ }
+
public static void checkContains(Collection<String> snippets, List<Diagnostic> diagnostics) {
snippets.forEach(snippet -> checkContains(snippet, diagnostics));
}
+ public static void checkNotContains(Collection<String> snippets, List<Diagnostic> diagnostics) {
+ snippets.forEach(snippet -> checkNotContains(snippet, diagnostics));
+ }
+
public void checkErrorsContains(String snippet) {
checkContains(snippet, errors);
}
diff --git a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
index 9a36a04..bee542f 100644
--- a/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
+++ b/src/test/java/com/android/tools/r8/KotlinCompilerTool.java
@@ -21,6 +21,7 @@
import java.util.Collection;
import java.util.Collections;
import java.util.List;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.junit.rules.TemporaryFolder;
@@ -29,29 +30,35 @@
public static final class KotlinCompiler {
private final String name;
- private final Path path;
+ private final Path lib;
+ private final Path compiler;
- public KotlinCompiler(String name, Path path) {
+ public KotlinCompiler(String name) {
this.name = name;
- this.path = path;
+ this.lib = Paths.get(ToolHelper.THIRD_PARTY_DIR, "kotlin", name, "kotlinc", "lib");
+ this.compiler = lib.resolve("kotlin-compiler.jar");
}
- public Path getPath() {
- return path;
+ public KotlinCompiler(String name, Path compiler) {
+ this.name = name;
+ this.compiler = compiler;
+ this.lib = null;
+ }
+
+ public Path getCompiler() {
+ return compiler;
+ }
+
+ public Path getFolder() {
+ return lib;
+ }
+
+ @Override
+ public String toString() {
+ return name;
}
}
- public static KotlinCompiler KOTLINC =
- new KotlinCompiler(
- "kotlinc",
- Paths.get(
- ToolHelper.THIRD_PARTY_DIR,
- "kotlin",
- "kotlin-compiler-1.3.72",
- "kotlinc",
- "lib",
- "kotlin-compiler.jar"));
-
private final CfRuntime jdk;
private final TestState state;
private final KotlinCompiler compiler;
@@ -70,6 +77,14 @@
this.targetVersion = targetVersion;
}
+ public KotlinCompiler getCompiler() {
+ return compiler;
+ }
+
+ public KotlinTargetVersion getTargetVersion() {
+ return targetVersion;
+ }
+
public static KotlinCompilerTool create(
CfRuntime jdk,
TemporaryFolder temp,
@@ -104,6 +119,24 @@
return addSourceFilesWithNonKtExtension(temp, Arrays.asList(files));
}
+ public KotlinCompilerTool includeRuntime() {
+ assert !additionalArguments.contains("-include-runtime");
+ addArguments("-include-runtime");
+ return this;
+ }
+
+ public KotlinCompilerTool noReflect() {
+ assert !additionalArguments.contains("-no-reflect");
+ addArguments("-no-reflect");
+ return this;
+ }
+
+ public KotlinCompilerTool noStdLib() {
+ assert !additionalArguments.contains("-no-stdlib");
+ addArguments("-no-stdlib");
+ return this;
+ }
+
public KotlinCompilerTool addSourceFilesWithNonKtExtension(
TemporaryFolder temp, Collection<Path> files) {
return addSourceFiles(
@@ -145,6 +178,11 @@
return this;
}
+ public KotlinCompilerTool apply(Consumer<KotlinCompilerTool> consumer) {
+ consumer.accept(this);
+ return this;
+ }
+
private Path getOrCreateOutputPath() throws IOException {
return output != null ? output : state.getNewTempFolder().resolve("out.jar");
}
@@ -167,7 +205,7 @@
List<String> cmdline = new ArrayList<>();
cmdline.add(jdk.getJavaExecutable().toString());
cmdline.add("-cp");
- cmdline.add(compiler.getPath().toString());
+ cmdline.add(compiler.getCompiler().toString());
cmdline.add(ToolHelper.K2JVMCompiler);
if (useJvmAssertions) {
cmdline.add("-Xassertions=jvm");
diff --git a/src/test/java/com/android/tools/r8/KotlinTestBase.java b/src/test/java/com/android/tools/r8/KotlinTestBase.java
index 6cd9cfd..f8dc222 100644
--- a/src/test/java/com/android/tools/r8/KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/KotlinTestBase.java
@@ -5,6 +5,8 @@
import static org.hamcrest.CoreMatchers.containsString;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
@@ -12,13 +14,19 @@
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
import java.util.List;
+import java.util.Map;
+import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.hamcrest.Matcher;
public abstract class KotlinTestBase extends TestBase {
- protected static final String checkParameterIsNotNullSignature =
+ protected static final String checkParameterIsNotNullSignature =
"void kotlin.jvm.internal.Intrinsics.checkParameterIsNotNull("
+ "java.lang.Object, java.lang.String)";
protected static final String throwParameterIsNotNullExceptionSignature =
@@ -29,10 +37,14 @@
private static final String RSRC = "kotlinR8TestResources";
+ private static final Map<String, KotlinCompileMemoizer> compileMemoizers = new HashMap<>();
+
+ protected final KotlinCompiler kotlinc;
protected final KotlinTargetVersion targetVersion;
- protected KotlinTestBase(KotlinTargetVersion targetVersion) {
+ protected KotlinTestBase(KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
this.targetVersion = targetVersion;
+ this.kotlinc = kotlinc;
}
protected static List<Path> getKotlinFilesInTestPackage(Package pkg) throws IOException {
@@ -42,8 +54,7 @@
.collect(Collectors.toList());
}
- protected static Path getKotlinFileInTestPackage(Package pkg, String fileName)
- throws IOException {
+ protected static Path getKotlinFileInTestPackage(Package pkg, String fileName) {
String folder = DescriptorUtils.getBinaryNameFromJavaType(pkg.getName());
return getKotlinFileInTest(folder, fileName);
}
@@ -56,9 +67,14 @@
return Paths.get(ToolHelper.TESTS_DIR, RSRC, folder, fileName + FileUtils.KT_EXTENSION);
}
- protected Path getKotlinJarFile(String folder) {
- return Paths.get(ToolHelper.TESTS_BUILD_DIR, RSRC,
- targetVersion.getFolderName(), folder + FileUtils.JAR_EXTENSION);
+ protected static List<Path> getKotlinFilesInResource(String folder) {
+ try {
+ return Files.walk(Paths.get(ToolHelper.TESTS_DIR, RSRC, folder))
+ .filter(path -> path.toString().endsWith(".kt") || path.toString().endsWith(".java"))
+ .collect(Collectors.toList());
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
protected Path getJavaJarFile(String folder) {
@@ -73,4 +89,60 @@
protected static Matcher<String> expectedInfoMessagesFromKotlinStdLib() {
return containsString("No VersionRequirement");
}
+
+ protected KotlinCompilerTool kotlinCompilerTool() {
+ return KotlinCompilerTool.create(CfRuntime.getCheckedInJdk9(), temp, kotlinc, targetVersion);
+ }
+
+ public static KotlinCompileMemoizer getCompileMemoizer(Path... source) {
+ return new KotlinCompileMemoizer(Arrays.asList(source));
+ }
+
+ public static KotlinCompileMemoizer getCompileMemoizer(Collection<Path> sources) {
+ assert sources.size() > 0;
+ return new KotlinCompileMemoizer(sources);
+ }
+
+ public static KotlinCompileMemoizer getCompileMemoizer(
+ Collection<Path> sources, String sharedFolder) {
+ return compileMemoizers.computeIfAbsent(
+ sharedFolder, ignore -> new KotlinCompileMemoizer(sources));
+ }
+
+ public static class KotlinCompileMemoizer {
+
+ private final Collection<Path> sources;
+ private Consumer<KotlinCompilerTool> kotlinCompilerToolConsumer = x -> {};
+ private final Map<KotlinCompiler, Map<KotlinTargetVersion, Path>> compiledPaths =
+ new IdentityHashMap<>();
+
+ public KotlinCompileMemoizer(Collection<Path> sources) {
+ this.sources = sources;
+ }
+
+ public KotlinCompileMemoizer configure(Consumer<KotlinCompilerTool> consumer) {
+ this.kotlinCompilerToolConsumer = consumer;
+ return this;
+ }
+
+ public Path getForConfiguration(KotlinCompiler compiler, KotlinTargetVersion targetVersion) {
+ Map<KotlinTargetVersion, Path> kotlinTargetVersionPathMap = compiledPaths.get(compiler);
+ if (kotlinTargetVersionPathMap == null) {
+ kotlinTargetVersionPathMap = new IdentityHashMap<>();
+ compiledPaths.put(compiler, kotlinTargetVersionPathMap);
+ }
+ return kotlinTargetVersionPathMap.computeIfAbsent(
+ targetVersion,
+ ignored -> {
+ try {
+ return kotlinc(compiler, targetVersion)
+ .addSourceFiles(sources)
+ .apply(kotlinCompilerToolConsumer)
+ .compile();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/R8CfVersionTest.java b/src/test/java/com/android/tools/r8/R8CfVersionTest.java
new file mode 100644
index 0000000..4f051ad
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/R8CfVersionTest.java
@@ -0,0 +1,54 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.io.IOException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class R8CfVersionTest extends TestBase {
+
+ private final CfVersion targetVersion = CfVersion.V1_8;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public R8CfVersionTest(TestParameters parameters) {}
+
+ @Test
+ public void testCfVersionR8() throws IOException {
+ CodeInspector inspector = new CodeInspector(ToolHelper.R8_WITH_DEPS_JAR);
+ inspector.forAllClasses(
+ clazz -> {
+ assertTrue(
+ clazz
+ .getDexProgramClass()
+ .getInitialClassFileVersion()
+ .isLessThanOrEqualTo(targetVersion));
+ });
+ }
+
+ @Test
+ public void testCfVersionR8Lib() throws IOException {
+ CodeInspector inspector = new CodeInspector(ToolHelper.R8LIB_JAR);
+ inspector.forAllClasses(
+ clazz -> {
+ assertTrue(
+ clazz
+ .getDexProgramClass()
+ .getInitialClassFileVersion()
+ .isLessThanOrEqualTo(targetVersion));
+ });
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/R8TestRunResult.java b/src/test/java/com/android/tools/r8/R8TestRunResult.java
index 0afdccf..bbd5836 100644
--- a/src/test/java/com/android/tools/r8/R8TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestRunResult.java
@@ -94,8 +94,7 @@
}
public <E extends Throwable> R8TestRunResult inspectStackTrace(
- ThrowingBiConsumer<StackTrace, CodeInspector, E> consumer)
- throws E, IOException, ExecutionException {
+ ThrowingBiConsumer<StackTrace, CodeInspector, E> consumer) throws E, IOException {
consumer.accept(getStackTrace(), new CodeInspector(app, proguardMap));
return self();
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 5669af0..e1d4c9e 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -1702,6 +1702,16 @@
return AndroidApiLevel.L;
}
+ public static boolean canUseJavaUtilObjects(TestParameters parameters) {
+ return parameters.isCfRuntime()
+ || parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.K);
+ }
+
+ public static boolean canUseRequireNonNull(TestParameters parameters) {
+ return parameters.isDexRuntime()
+ && parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.K);
+ }
+
public Path compileToZip(
TestParameters parameters, Collection<Class<?>> classPath, Class<?>... compilationUnit)
throws Exception {
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index abdfb83..f196151 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -47,7 +47,7 @@
options -> {
options.testing.allowClassInlinerGracefulExit = false;
options.testing.reportUnusedProguardConfigurationRules = true;
- options.enableHorizontalClassMerging = true;
+ options.horizontalClassMergerOptions().enable();
};
final Backend backend;
@@ -130,7 +130,6 @@
public T addHorizontallyMergedClassesInspectorIf(
boolean condition, Consumer<HorizontallyMergedClassesInspector> inspector) {
-
if (condition) {
return addHorizontallyMergedClassesInspector(inspector);
}
diff --git a/src/test/java/com/android/tools/r8/TestParametersBuilder.java b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
index f93d6d6..9b84425 100644
--- a/src/test/java/com/android/tools/r8/TestParametersBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
@@ -19,10 +19,6 @@
public class TestParametersBuilder {
- // Static computation of VMs configured as available by the testing invocation.
- private static final List<TestRuntime> availableRuntimes =
- getAvailableRuntimes().collect(Collectors.toList());
-
// Predicate describing which test parameters are applicable to the test.
// Built via the methods found below. Defaults to no applicable parameters, i.e., the emtpy set.
private Predicate<TestParameters> filter = param -> false;
@@ -154,6 +150,7 @@
private Predicate<AndroidApiLevel> apiLevelFilter = param -> false;
private List<AndroidApiLevel> explicitApiLevels = new ArrayList<>();
+ private List<TestRuntime> customRuntimes = new ArrayList<>();
private TestParametersBuilder withApiFilter(Predicate<AndroidApiLevel> filter) {
enableApiLevels = true;
@@ -195,13 +192,23 @@
return withApiFilter(api -> api.getLevel() < endExclusive.getLevel());
}
+ public TestParametersBuilder withCustomRuntime(TestRuntime runtime) {
+ assert getUnfilteredAvailableRuntimes().noneMatch(r -> r == runtime);
+ customRuntimes.add(runtime);
+ return this;
+ }
+
public TestParametersCollection build() {
assert !enableApiLevels || enableApiLevelsForCf || hasDexRuntimeFilter;
- return new TestParametersCollection(
+ List<TestParameters> availableParameters =
getAvailableRuntimes()
.flatMap(this::createParameters)
.filter(filter)
- .collect(Collectors.toList()));
+ .collect(Collectors.toList());
+ List<TestParameters> customParameters =
+ customRuntimes.stream().flatMap(this::createParameters).collect(Collectors.toList());
+ availableParameters.addAll(customParameters);
+ return new TestParametersCollection(availableParameters);
}
public Stream<TestParameters> createParameters(TestRuntime runtime) {
diff --git a/src/test/java/com/android/tools/r8/TestRuntime.java b/src/test/java/com/android/tools/r8/TestRuntime.java
index db1ca7f..04b61c0 100644
--- a/src/test/java/com/android/tools/r8/TestRuntime.java
+++ b/src/test/java/com/android/tools/r8/TestRuntime.java
@@ -27,6 +27,7 @@
JDK9("jdk9", 53),
JDK10("jdk10", 54),
JDK11("jdk11", 55),
+ JDK15("jdk15", 59),
;
private final String name;
@@ -67,6 +68,7 @@
private static final Path JDK9_PATH =
Paths.get(ToolHelper.THIRD_PARTY_DIR, "openjdk", "openjdk-9.0.4");
private static final Path JDK11_PATH = Paths.get(ToolHelper.THIRD_PARTY_DIR, "openjdk", "jdk-11");
+ private static final Path JDK15_PATH = Paths.get(ToolHelper.THIRD_PARTY_DIR, "openjdk", "jdk-15");
public static CfRuntime getCheckedInJdk8() {
Path home;
@@ -81,30 +83,28 @@
return new CfRuntime(CfVm.JDK8, home);
}
- public static CfRuntime getCheckedInJdk9() {
- Path home;
+ private static Path getCheckedInJdkHome(Path path) {
if (ToolHelper.isLinux()) {
- home = JDK9_PATH.resolve("linux");
+ return path.resolve("linux");
} else if (ToolHelper.isMac()) {
- home = JDK9_PATH.resolve("osx");
+ return path.resolve("osx");
} else {
assert ToolHelper.isWindows();
- home = JDK9_PATH.resolve("windows");
+ return path.resolve("windows");
}
- return new CfRuntime(CfVm.JDK9, home);
+ }
+
+ public static CfRuntime getCheckedInJdk9() {
+ return new CfRuntime(CfVm.JDK9, getCheckedInJdkHome(JDK9_PATH));
}
public static CfRuntime getCheckedInJdk11() {
- Path home;
- if (ToolHelper.isLinux()) {
- home = JDK11_PATH.resolve("Linux");
- } else if (ToolHelper.isMac()) {
- home = Paths.get(JDK11_PATH.toString(), "Mac", "Contents", "Home");
- } else {
- assert ToolHelper.isWindows();
- home = JDK11_PATH.resolve("Windows");
- }
- return new CfRuntime(CfVm.JDK11, home);
+ return new CfRuntime(CfVm.JDK11, getCheckedInJdkHome(JDK11_PATH));
+ }
+
+ // TODO(b/169692487): Add this to 'getCheckedInCfRuntimes' when we start having support for JDK15.
+ public static CfRuntime getCheckedInJdk15() {
+ return new CfRuntime(CfVm.JDK15, getCheckedInJdkHome(JDK15_PATH));
}
public static List<CfRuntime> getCheckedInCfRuntimes() {
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 3ad6107..367a8f3 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -10,6 +10,7 @@
import static org.junit.Assert.fail;
import com.android.tools.r8.DeviceRunner.DeviceRunnerConfigurationException;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper.DexVm.Kind;
@@ -121,8 +122,8 @@
public static final String JAVA_CLASSES_DIR = BUILD_DIR + "classes/java/";
public static final String JDK_11_TESTS_CLASSES_DIR = JAVA_CLASSES_DIR + "jdk11Tests/";
- public static final String ASM_JAR = BUILD_DIR + "deps/asm-8.0.jar";
- public static final String ASM_UTIL_JAR = BUILD_DIR + "deps/asm-util-8.0.jar";
+ public static final String ASM_JAR = BUILD_DIR + "deps/asm-9.0.jar";
+ public static final String ASM_UTIL_JAR = BUILD_DIR + "deps/asm-util-9.0.jar";
public static final Path API_SAMPLE_JAR = Paths.get("tests", "r8_api_usage_sample.jar");
@@ -140,17 +141,7 @@
public static final String RHINO_ANDROID_JAR =
"third_party/rhino-android-1.1.1/rhino-android-1.1.1.jar";
public static final String RHINO_JAR = "third_party/rhino-1.7.10/rhino-1.7.10.jar";
- static final String KT_PRELOADER =
- "third_party/kotlin/kotlin-compiler-1.3.72/kotlinc/lib/kotlin-preloader.jar";
- public static final String KT_COMPILER =
- "third_party/kotlin/kotlin-compiler-1.3.72/kotlinc/lib/kotlin-compiler.jar";
public static final String K2JVMCompiler = "org.jetbrains.kotlin.cli.jvm.K2JVMCompiler";
- public static final String KT_STDLIB =
- "third_party/kotlin/kotlin-compiler-1.3.72/kotlinc/lib/kotlin-stdlib.jar";
- public static final String KT_REFLECT =
- "third_party/kotlin/kotlin-compiler-1.3.72/kotlinc/lib/kotlin-reflect.jar";
- public static final String KT_SCRIPT_RT =
- "third_party/kotlin/kotlin-compiler-1.3.72/kotlinc/lib/kotlin-script-runtime.jar";
private static final String ANDROID_JAR_PATTERN = "third_party/android_jar/lib-v%d/android.jar";
private static final AndroidApiLevel DEFAULT_MIN_SDK = AndroidApiLevel.I;
@@ -280,10 +271,18 @@
return compareTo(other) > 0;
}
+ public boolean isNewerThanOrEqual(Version other) {
+ return compareTo(other) >= 0;
+ }
+
public boolean isAtLeast(Version other) {
return compareTo(other) >= 0;
}
+ public boolean isOlderThan(Version other) {
+ return compareTo(other) < 0;
+ }
+
public boolean isOlderThanOrEqual(Version other) {
return compareTo(other) <= 0;
}
@@ -841,16 +840,22 @@
throw new Unreachable("Unable to find a most recent android.jar");
}
- public static Path getKotlinStdlibJar() {
- Path path = Paths.get(KT_STDLIB);
- assert Files.exists(path) : "Expected kotlin stdlib jar";
- return path;
+ public static Path getKotlinStdlibJar(KotlinCompiler kotlinc) {
+ Path stdLib = kotlinc.getFolder().resolve("kotlin-stdlib.jar");
+ assert Files.exists(stdLib) : "Expected kotlin stdlib jar";
+ return stdLib;
}
- public static Path getKotlinReflectJar() {
- Path path = Paths.get(KT_REFLECT);
- assert Files.exists(path) : "Expected kotlin reflect jar";
- return path;
+ public static Path getKotlinReflectJar(KotlinCompiler kotlinc) {
+ Path reflectJar = kotlinc.getFolder().resolve("kotlin-reflect.jar");
+ assert Files.exists(reflectJar) : "Expected kotlin reflect jar";
+ return reflectJar;
+ }
+
+ public static Path getKotlinScriptRuntime(KotlinCompiler kotlinc) {
+ Path reflectJar = kotlinc.getFolder().resolve("kotlin-script-runtime.jar");
+ assert Files.exists(reflectJar) : "Expected kotlin script runtime jar";
+ return reflectJar;
}
public static Path getJdwpTestsCfJarPath(AndroidApiLevel minSdk) {
@@ -1355,41 +1360,6 @@
return runJava(runtime, ImmutableList.of(), classpath, args);
}
- @Deprecated
- public static ProcessResult runKotlinc(
- List<Path> classPaths,
- Path directoryToCompileInto,
- List<String> extraOptions,
- Path... filesToCompile)
- throws IOException {
- List<String> cmdline = new ArrayList<>(Arrays.asList(getJavaExecutable()));
- cmdline.add("-jar");
- cmdline.add(KT_PRELOADER);
- cmdline.add("org.jetbrains.kotlin.preloading.Preloader");
- cmdline.add("-cp");
- cmdline.add(KT_COMPILER);
- cmdline.add(K2JVMCompiler);
- String[] strings = Arrays.stream(filesToCompile).map(Path::toString).toArray(String[]::new);
- Collections.addAll(cmdline, strings);
- cmdline.add("-d");
- cmdline.add(directoryToCompileInto.toString());
- List<String> cp = classPaths == null ? null
- : classPaths.stream().map(Path::toString).collect(Collectors.toList());
- if (cp != null) {
- cmdline.add("-cp");
- if (isWindows()) {
- cmdline.add(String.join(";", cp));
- } else {
- cmdline.add(String.join(":", cp));
- }
- }
- if (extraOptions != null) {
- cmdline.addAll(extraOptions);
- }
- ProcessBuilder builder = new ProcessBuilder(cmdline);
- return ToolHelper.runProcess(builder);
- }
-
public static ProcessResult runJava(
CfRuntime runtime, List<String> vmArgs, List<Path> classpath, String... args)
throws IOException {
@@ -2160,6 +2130,14 @@
}
}
+ public static KotlinCompiler getKotlinC_1_3_72() {
+ return new KotlinCompiler("kotlin-compiler-1.3.72");
+ }
+
+ public static KotlinCompiler[] getKotlinCompilers() {
+ return new KotlinCompiler[] {getKotlinC_1_3_72()};
+ }
+
public static void disassemble(AndroidApp app, PrintStream ps)
throws IOException, ExecutionException {
DexApplication application =
diff --git a/src/test/java/com/android/tools/r8/annotations/SourceDebugExtensionTest.java b/src/test/java/com/android/tools/r8/annotations/SourceDebugExtensionTest.java
index 524cbfa..607f96d 100644
--- a/src/test/java/com/android/tools/r8/annotations/SourceDebugExtensionTest.java
+++ b/src/test/java/com/android/tools/r8/annotations/SourceDebugExtensionTest.java
@@ -4,16 +4,16 @@
package com.android.tools.r8.annotations;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
@@ -25,6 +25,7 @@
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.List;
import java.util.concurrent.ExecutionException;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -35,14 +36,17 @@
public class SourceDebugExtensionTest extends TestBase {
private final TestParameters parameters;
+ private final KotlinCompiler kotlinCompiler;
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimesAndApiLevels().build();
+ @Parameters(name = "{0}, kotlinc: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(), getKotlinCompilers());
}
- public SourceDebugExtensionTest(TestParameters parameters) {
+ public SourceDebugExtensionTest(TestParameters parameters, KotlinCompiler kotlinCompiler) {
this.parameters = parameters;
+ this.kotlinCompiler = kotlinCompiler;
}
@Test
@@ -50,7 +54,7 @@
CfRuntime cfRuntime =
parameters.isCfRuntime() ? parameters.getRuntime().asCf() : TestRuntime.getCheckedInJdk9();
Path kotlinSources =
- kotlinc(cfRuntime, getStaticTemp(), KOTLINC, KotlinTargetVersion.JAVA_8)
+ kotlinc(cfRuntime, getStaticTemp(), kotlinCompiler, KotlinTargetVersion.JAVA_8)
.addSourceFiles(
getFilesInTestFolderRelativeToClass(
KotlinInlineFunctionRetraceTest.class, "kt", ".kt"))
@@ -58,7 +62,7 @@
CodeInspector kotlinInspector = new CodeInspector(kotlinSources);
inspectSourceDebugExtension(kotlinInspector);
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinCompiler))
.addProgramFiles(kotlinSources)
.addKeepAttributes(ProguardKeepAttributes.SOURCE_DEBUG_EXTENSION)
.addKeepAllClassesRule()
diff --git a/src/test/java/com/android/tools/r8/cf/bootstrap/KotlinCompilerTreeShakingTest.java b/src/test/java/com/android/tools/r8/cf/bootstrap/KotlinCompilerTreeShakingTest.java
index 693eced..7aa4205 100644
--- a/src/test/java/com/android/tools/r8/cf/bootstrap/KotlinCompilerTreeShakingTest.java
+++ b/src/test/java/com/android/tools/r8/cf/bootstrap/KotlinCompilerTreeShakingTest.java
@@ -3,13 +3,12 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.cf.bootstrap;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.internal.CompilationTestBase;
@@ -38,27 +37,29 @@
"Hello.kt");
private static final int MAX_SIZE = (int) (31361268 * 0.4);
- private TestParameters parameters;
+ private final TestParameters parameters;
+ private final KotlinCompiler kotlinCompiler;
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withCfRuntimes().build();
+ @Parameters(name = "{0}, kotlinc: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(getTestParameters().withCfRuntimes().build(), getKotlinCompilers());
}
- public KotlinCompilerTreeShakingTest(TestParameters parameters) {
+ public KotlinCompilerTreeShakingTest(TestParameters parameters, KotlinCompiler kotlinCompiler) {
this.parameters = parameters;
+ this.kotlinCompiler = kotlinCompiler;
}
@Test
public void testForRuntime() throws Exception {
// Compile Hello.kt and make sure it works as expected.
Path classPathBefore =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, KotlinTargetVersion.JAVA_8)
+ kotlinc(parameters.getRuntime().asCf(), kotlinCompiler, KotlinTargetVersion.JAVA_8)
.addSourceFiles(HELLO_KT)
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar())
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinCompiler))
.addClasspath(classPathBefore)
.run(parameters.getRuntime(), PKG_NAME + ".HelloKt")
.assertSuccessWithOutputLines("I'm Woody. Howdy, howdy, howdy.");
@@ -69,41 +70,40 @@
+ "b/144877828: assertion error in method naming state during interface method renaming; "
+ "b/144859533: umbrella"
)
+
@Test
public void test() throws Exception {
List<Path> libs =
ImmutableList.of(
- ToolHelper.getKotlinStdlibJar(),
- ToolHelper.getKotlinReflectJar(),
- Paths.get(ToolHelper.KT_SCRIPT_RT));
+ ToolHelper.getKotlinStdlibJar(kotlinCompiler),
+ ToolHelper.getKotlinReflectJar(kotlinCompiler),
+ ToolHelper.getKotlinScriptRuntime(kotlinCompiler));
// Process kotlin-compiler.jar.
Path r8ProcessedKotlinc =
testForR8(parameters.getBackend())
.addLibraryFiles(libs)
.addLibraryFiles(ToolHelper.getJava8RuntimeJar())
- .addProgramFiles(Paths.get(ToolHelper.KT_COMPILER))
+ .addProgramFiles(kotlinCompiler.getCompiler())
.addKeepAttributes("*Annotation*")
.addKeepClassAndMembersRules(ToolHelper.K2JVMCompiler)
.addKeepClassAndMembersRules("**.K2JVMCompilerArguments")
.addKeepClassAndMembersRules("**.*Argument*")
.addKeepClassAndMembersRules("**.Freezable")
.addKeepRules(
- "-keepclassmembers class * {",
- " *** parseCommandLineArguments(...);",
- "}"
- )
+ "-keepclassmembers class * {", " *** parseCommandLineArguments(...);", "}")
.addKeepRules(
"-keepclassmembers,allowoptimization enum * {",
" public static **[] values();",
" public static ** valueOf(java.lang.String);",
"}")
- .addOptionsModification(o -> {
- // Ignore com.sun.tools.javac.main.JavaCompiler and others
- // Resulting jar may not be able to deal with .java source files, though.
- o.ignoreMissingClasses = true;
- // b/144861100: invoke-static on interface is allowed up to JDK 8.
- o.testing.allowInvokeErrors = true;
- })
+ .addOptionsModification(
+ o -> {
+ // Ignore com.sun.tools.javac.main.JavaCompiler and others
+ // Resulting jar may not be able to deal with .java source files, though.
+ o.ignoreMissingClasses = true;
+ // b/144861100: invoke-static on interface is allowed up to JDK 8.
+ o.testing.allowInvokeErrors = true;
+ })
.compile()
.writeToZip();
@@ -125,7 +125,7 @@
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar())
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinCompiler))
.addClasspath(classPathAfter)
.run(parameters.getRuntime(), PKG_NAME + ".HelloKt")
.assertSuccessWithOutputLines("I'm Woody. Howdy, howdy, howdy.");
diff --git a/src/test/java/com/android/tools/r8/classFiltering/ClassFilteringTest.java b/src/test/java/com/android/tools/r8/classFiltering/ClassFilteringTest.java
index 3c6aab6..f8a97c4 100644
--- a/src/test/java/com/android/tools/r8/classFiltering/ClassFilteringTest.java
+++ b/src/test/java/com/android/tools/r8/classFiltering/ClassFilteringTest.java
@@ -4,11 +4,8 @@
package com.android.tools.r8.classFiltering;
-import com.android.tools.r8.ArchiveProgramResourceProvider;
import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.ProgramResource;
-import com.android.tools.r8.ProgramResourceProvider;
-import com.android.tools.r8.ResourceException;
+import com.android.tools.r8.OutputMode;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -118,14 +115,16 @@
@Test
public void testDexMergingWithChecksumMissing() throws Exception {
- // Step #1: Build the dex file seperately as an incremental build tools usually do but this time
+ // Step #1: Build the dex file separately as an incremental build tools usually do but this time
// make one of the dex file missing checksum information.
- Path[] dexInput = new Path[] {
- buildDex(TestClass.class,true, null),
- buildDex(TestClass.Keep.class,true, null),
- buildDex(TestClass.Remove.class, false, null)};
+ Path[] dexInput =
+ new Path[] {
+ buildDex(TestClass.class, true, null),
+ buildDex(TestClass.Keep.class, true, null),
+ buildDex(TestClass.Remove.class, false, null)
+ };
- // Step #2: Now use D8 as a merging tool and verify that the compilation fails as expect.
+ // Step #2: Now use D8 as a merging tool and verify that the compilation fails as expected.
try {
testForD8()
.setMinApi(parameters.getApiLevel())
@@ -140,10 +139,8 @@
}
}
- /*
@Test
- public void testMultidexOutput()
- throws CompilationFailedException, IOException, ExecutionException, ResourceException {
+ public void testDexFilePerClassFilteringOutput() throws Exception {
// Step #1: Build the program pretending to be multidex files with DexPerClass.
final Path outZip = testForD8()
.setMinApi(parameters.getApiLevel())
@@ -153,22 +150,15 @@
.compile()
.writeToZip();
- final long crc = ToolHelper.getClassByteCrc(TestClass.Remove.class);
-
// Step #2: Verify that the checksums are present and filtering is working as expected.
- ProgramResourceProvider filter = new ArchiveProvider(outZip) {
- @Override
- public boolean includeClassWithChecksum(String classDescriptor, Long checksum) {
- return !checksum.equals(crc);
- }
- };
+ final long crc = ToolHelper.getClassByteCrc(TestClass.Remove.class);
testForD8()
- .addProgramResourceProvider(filter)
+ .addProgramFiles(outZip)
+ .apply(b -> b.getBuilder().setDexClassChecksumFilter((desc, checksum) -> checksum != crc))
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput("Keep No Remove ");
}
- */
@Test
public void testLambdaChecksum() throws Exception {
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingNonTrivialTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingNonTrivialTest.java
index 4d7d7fe..42df5c0 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingNonTrivialTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingNonTrivialTest.java
@@ -23,7 +23,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addHorizontallyMergedClassesInspectorIf(
enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class))
.enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingTest.java
index cc092e9..3b0af4f 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/AbstractMethodMergingTest.java
@@ -23,7 +23,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addHorizontallyMergedClassesInspectorIf(
enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class))
.enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptResourceFileContentsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptResourceFileContentsTest.java
index 2c4ac9d..db8d4c7 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptResourceFileContentsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptResourceFileContentsTest.java
@@ -36,7 +36,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addOptionsModification(options -> options.dataResourceConsumer = dataResourceConsumer)
.enableNeverClassInliningAnnotations()
.addDataEntryResources(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptVerticallyMergedResourceFileContentsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptVerticallyMergedResourceFileContentsTest.java
index ea50082..0ebbb9d 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptVerticallyMergedResourceFileContentsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/AdaptVerticallyMergedResourceFileContentsTest.java
@@ -35,7 +35,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addOptionsModification(options -> options.dataResourceConsumer = dataResourceConsumer)
.enableNeverClassInliningAnnotations()
.addDataEntryResources(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassWithInstanceFieldsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassWithInstanceFieldsTest.java
index 25bb4ec..31a49cc 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassWithInstanceFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassWithInstanceFieldsTest.java
@@ -25,7 +25,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectCheckCastTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectCheckCastTest.java
index 745fc26..bc5380e 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectCheckCastTest.java
@@ -24,7 +24,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectInstanceOfTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectInstanceOfTest.java
index 6a61d2f..6551ad2 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByDirectInstanceOfTest.java
@@ -24,7 +24,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java
index 5eb49b1..6017cbe 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java
@@ -26,7 +26,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNoVerticalClassMergingAnnotations()
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java
index 70e7c0d..cf05da6 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java
@@ -26,7 +26,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentInterfacesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentInterfacesTest.java
index 3c9d066..5abdc09 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentInterfacesTest.java
@@ -26,7 +26,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentVisibilityFieldsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentVisibilityFieldsTest.java
index 90e407e..68a81b1 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentVisibilityFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithDifferentVisibilityFieldsTest.java
@@ -32,7 +32,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithFeatureSplitTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithFeatureSplitTest.java
index 5907c15..9ac569b 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithFeatureSplitTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithFeatureSplitTest.java
@@ -42,7 +42,8 @@
.addKeepFeatureMainRule(Feature1Main.class)
.addKeepFeatureMainRule(Feature2Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithIdenticalInterfacesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithIdenticalInterfacesTest.java
index 2bab975..6714388 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithIdenticalInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithIdenticalInterfacesTest.java
@@ -25,7 +25,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithNativeMethodsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithNativeMethodsTest.java
index 5ee01b3..1f0e3e6 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithNativeMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithNativeMethodsTest.java
@@ -26,7 +26,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithOverlappingVisibilitiesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithOverlappingVisibilitiesTest.java
index 565c1bd..608f6fe 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithOverlappingVisibilitiesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithOverlappingVisibilitiesTest.java
@@ -29,7 +29,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithStaticFields.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithStaticFields.java
index f00e07e..2810ce8 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithStaticFields.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesWithStaticFields.java
@@ -23,7 +23,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.addHorizontallyMergedClassesInspectorIf(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/CompanionClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/CompanionClassMergingTest.java
index b14763f..9aca9fe 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/CompanionClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/CompanionClassMergingTest.java
@@ -27,7 +27,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addOptionsModification(options -> options.enableClassInlining = false)
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/CompatKeepConstructorLiveTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/CompatKeepConstructorLiveTest.java
index 9ccc2d4..c03361f 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/CompatKeepConstructorLiveTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/CompatKeepConstructorLiveTest.java
@@ -25,7 +25,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java
index 2383a03..935e75e 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorCantInlineTest.java
@@ -27,7 +27,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingAfterUnusedArgumentRemovalTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingAfterUnusedArgumentRemovalTest.java
index 32f7454..d38efb3 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingAfterUnusedArgumentRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingAfterUnusedArgumentRemovalTest.java
@@ -22,7 +22,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.addHorizontallyMergedClassesInspectorIf(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java
index 185e090..8936dc1 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingOverlapTest.java
@@ -32,7 +32,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java
index f658909..f878fd5 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingPreoptimizedTest.java
@@ -33,7 +33,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addHorizontallyMergedClassesInspectorIf(
enableHorizontalClassMerging,
inspector ->
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTest.java
index b1d77c2..21c3486 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTest.java
@@ -23,7 +23,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java
index f6def29..50da81e 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingTrivialOverlapTest.java
@@ -32,7 +32,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingWithArgumentsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingWithArgumentsTest.java
index a4a0fd9..7891de2 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingWithArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ConstructorMergingWithArgumentsTest.java
@@ -26,7 +26,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/DistinguishExceptionClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/DistinguishExceptionClassesTest.java
index c751735..749ae58 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/DistinguishExceptionClassesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/DistinguishExceptionClassesTest.java
@@ -22,7 +22,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("test success")
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/EmptyClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/EmptyClassTest.java
index 4cdca16..5d63188 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/EmptyClassTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/EmptyClassTest.java
@@ -25,7 +25,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.addHorizontallyMergedClassesInspectorIf(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/FieldTypeMergedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/FieldTypeMergedTest.java
index 616c88a..58434a9 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/FieldTypeMergedTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/FieldTypeMergedTest.java
@@ -29,7 +29,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/GenericStaticFieldTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/GenericStaticFieldTest.java
index 9b86b43..af72afe 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/GenericStaticFieldTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/GenericStaticFieldTest.java
@@ -20,7 +20,8 @@
.addKeepMainRule(Main.class)
.addKeepRules("-keepattributes Signatures")
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
// .addHorizontallyMergedClassesInspectorIf(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/IdenticalFieldMembersTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/IdenticalFieldMembersTest.java
index 6968e1a..9dae7a2 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/IdenticalFieldMembersTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/IdenticalFieldMembersTest.java
@@ -23,7 +23,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritInterfaceWithDefaultTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritInterfaceWithDefaultTest.java
index 9bdaca6..b069bb1 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritInterfaceWithDefaultTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritInterfaceWithDefaultTest.java
@@ -30,7 +30,8 @@
.addKeepMainRule(Main.class)
.allowStdoutMessages()
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritOverrideInterfaceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritOverrideInterfaceTest.java
index cedee87..8c7644d 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritOverrideInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritOverrideInterfaceTest.java
@@ -24,7 +24,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritsFromLibraryClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritsFromLibraryClassTest.java
index cfafb12..575c2cd 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritsFromLibraryClassTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/InheritsFromLibraryClassTest.java
@@ -30,7 +30,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/InnerOuterClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/InnerOuterClassesTest.java
index 075448a..98e74e4 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/InnerOuterClassesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/InnerOuterClassesTest.java
@@ -22,7 +22,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.addKeepAttributes("InnerClasses", "EnclosingMethod")
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/InstantiatedAndUninstantiatedClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/InstantiatedAndUninstantiatedClassMergingTest.java
index a27fdbd..59e77dd 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/InstantiatedAndUninstantiatedClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/InstantiatedAndUninstantiatedClassMergingTest.java
@@ -36,7 +36,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(TestClass.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.addHorizontallyMergedClassesInspector(
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/JavaLambdaMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/JavaLambdaMergingTest.java
new file mode 100644
index 0000000..adabb3e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/JavaLambdaMergingTest.java
@@ -0,0 +1,91 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.classmerging.horizontal;
+
+import static com.android.tools.r8.ir.desugar.LambdaRewriter.LAMBDA_CLASS_NAME_PREFIX;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.utils.codeinspector.VerticallyMergedClassesInspector;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.junit.Test;
+
+public class JavaLambdaMergingTest extends HorizontalClassMergingTestBase {
+
+ public JavaLambdaMergingTest(TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> {
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging);
+ assertFalse(options.horizontalClassMergerOptions().isJavaLambdaMergingEnabled());
+ options.horizontalClassMergerOptions().enableJavaLambdaMerging();
+ })
+ .addHorizontallyMergedClassesInspectorIf(
+ enableHorizontalClassMerging && parameters.isDexRuntime(),
+ inspector -> {
+ Set<DexType> lambdaSources =
+ inspector.getSources().stream()
+ .filter(x -> x.toSourceString().contains(LAMBDA_CLASS_NAME_PREFIX))
+ .collect(Collectors.toSet());
+ assertEquals(3, lambdaSources.size());
+ DexType firstTarget = inspector.getTarget(lambdaSources.iterator().next());
+ for (DexType lambdaSource : lambdaSources) {
+ assertTrue(
+ inspector
+ .getTarget(lambdaSource)
+ .toSourceString()
+ .contains(LAMBDA_CLASS_NAME_PREFIX));
+ assertEquals(firstTarget, inspector.getTarget(lambdaSource));
+ }
+ })
+ .addVerticallyMergedClassesInspector(
+ VerticallyMergedClassesInspector::assertNoClassesMerged)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ HelloGreeter helloGreeter =
+ System.currentTimeMillis() > 0
+ ? () -> System.out.print("Hello")
+ : () -> {
+ throw new RuntimeException();
+ };
+ WorldGreeter worldGreeter =
+ System.currentTimeMillis() > 0
+ ? () -> System.out.println(" world!")
+ : () -> {
+ throw new RuntimeException();
+ };
+ helloGreeter.hello();
+ worldGreeter.world();
+ }
+ }
+
+ interface HelloGreeter {
+
+ void hello();
+ }
+
+ interface WorldGreeter {
+
+ void world();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/LargeConstructorsMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/LargeConstructorsMergingTest.java
index 847db55..a553abe 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/LargeConstructorsMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/LargeConstructorsMergingTest.java
@@ -26,7 +26,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addOptionsModification(options -> options.testing.verificationSizeLimitInBytesOverride = 4)
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergeNonFinalAndFinalClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergeNonFinalAndFinalClassTest.java
index a5eb885..c8a36b6 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergeNonFinalAndFinalClassTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergeNonFinalAndFinalClassTest.java
@@ -25,7 +25,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addHorizontallyMergedClassesInspectorIf(
enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class))
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergePackagePrivateWithPublicClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergePackagePrivateWithPublicClassTest.java
index a1c8faa..04d69b1d 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergePackagePrivateWithPublicClassTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergePackagePrivateWithPublicClassTest.java
@@ -27,7 +27,8 @@
PackagePrivateClassRunner.class, PackagePrivateClassRunner.getPrivateClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java
index 2256e5d..f913560 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java
@@ -32,7 +32,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
index fc4f076..a11a7d6 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
@@ -46,7 +46,8 @@
.addKeepAttributeLineNumberTable()
.addKeepAttributeSourceFile()
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
@@ -63,7 +64,9 @@
2,
StackTraceLine.builder()
.setClassName(A.class.getTypeName())
- .setMethodName("<init>")
+ // TODO(b/124483578): The synthetic method should not be part of the
+ // retraced stack trace.
+ .setMethodName("$r8$init$bridge")
.setFileName(getClass().getSimpleName() + ".java")
.setLineNumber(0)
.build())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java
index 00d6e59..8c9d11d 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedVirtualMethodStackTraceTest.java
@@ -46,7 +46,8 @@
.addKeepAttributeSourceFile()
.addDontWarn(C.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
@@ -64,7 +65,6 @@
StackTrace expectedStackTraceWithMergedMethod =
StackTrace.builder()
.add(expectedStackTrace)
-
.add(
1,
StackTraceLine.builder()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergingProducesFieldCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergingProducesFieldCollisionTest.java
index d25d516..34972f6 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergingProducesFieldCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergingProducesFieldCollisionTest.java
@@ -31,7 +31,8 @@
.addProgramClassFileData(transformedC)
.addProgramClasses(Parent.class, A.class, B.class, Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java
index 5edc29f..b416826 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NestClassTest.java
@@ -58,7 +58,8 @@
.addKeepMainRule(examplesTypeName(BasicNestHostHorizontalClassMerging.class))
.addExamplesProgramFiles(R.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.compile()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAbstractClassesWithNonAbstractClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAbstractClassesWithNonAbstractClassesTest.java
index 2bc2c97..5566f45 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAbstractClassesWithNonAbstractClassesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAbstractClassesWithNonAbstractClassesTest.java
@@ -26,7 +26,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoClassesOrMembersWithAnnotationsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoClassesOrMembersWithAnnotationsTest.java
index d17fa75..74d0ad6 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoClassesOrMembersWithAnnotationsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoClassesOrMembersWithAnnotationsTest.java
@@ -31,7 +31,8 @@
.addKeepMainRule(Main.class)
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoHorizontalClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoHorizontalClassMergingTest.java
index dc513c3..5c0e207 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoHorizontalClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoHorizontalClassMergingTest.java
@@ -24,7 +24,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNoHorizontalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessOnMergedClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessOnMergedClassTest.java
index e357250..671f740 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessOnMergedClassTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessOnMergedClassTest.java
@@ -26,7 +26,8 @@
.addInnerClasses(NonReboundFieldAccessOnMergedClassTestClasses.class)
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addHorizontallyMergedClassesInspector(
inspector -> {
if (enableHorizontalClassMerging) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessWithMergedTypeTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessWithMergedTypeTest.java
index 3afcfb2..b6183a3 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessWithMergedTypeTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NonReboundFieldAccessWithMergedTypeTest.java
@@ -27,7 +27,8 @@
.addInnerClasses(NonReboundFieldAccessWithMergedTypeTestClasses.class)
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addHorizontallyMergedClassesInspector(
inspector -> {
if (enableHorizontalClassMerging) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/OverlappingConstructorsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/OverlappingConstructorsTest.java
index fbd587d..c97e384 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/OverlappingConstructorsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/OverlappingConstructorsTest.java
@@ -25,7 +25,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java
index a1b0951..2732240 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java
@@ -28,7 +28,8 @@
.addProgramClasses(B.class)
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.allowAccessModification(false)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java
index cdaeee7..4d7c0c4 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java
@@ -27,7 +27,8 @@
.addProgramClasses(D.class)
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.allowAccessModification(false)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberReferenceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberReferenceTest.java
index 4a22fe3..2f01f90 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberReferenceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberReferenceTest.java
@@ -28,7 +28,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.noMinification()
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberTest.java
index 444d573..1e09a5a 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberTest.java
@@ -23,7 +23,8 @@
.addKeepMainRule(Main.class)
.addKeepRules("-keepclassmembers class " + B.class.getTypeName() + " { void foo(); }")
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassTest.java
index a2b36f3..0ba06e6 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassTest.java
@@ -23,7 +23,8 @@
.addKeepMainRule(Main.class)
.addKeepClassRules(B.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexListTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexListTest.java
index 4a50200..e3e1b85 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexListTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexListTest.java
@@ -48,7 +48,7 @@
.addMainDexListClasses(A.class, Main.class)
.addOptionsModification(
options -> {
- options.enableHorizontalClassMerging = enableHorizontalClassMerging;
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging);
options.minimalMainDex = true;
})
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexTracingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexTracingTest.java
index 9e81bc6..6a31a5e 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexTracingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PreventMergeMainDexTracingTest.java
@@ -48,7 +48,7 @@
.addMainDexClassRules(Main.class)
.addOptionsModification(
options -> {
- options.enableHorizontalClassMerging = enableHorizontalClassMerging;
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging);
options.minimalMainDex = true;
})
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndInterfaceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndInterfaceMethodCollisionTest.java
index af37199..4553469 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndInterfaceMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndInterfaceMethodCollisionTest.java
@@ -25,7 +25,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addHorizontallyMergedClassesInspector(
HorizontallyMergedClassesInspector::assertNoClassesMerged)
.enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndStaticMethodCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndStaticMethodCollisionTest.java
index df03d8a..3c7b799 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndStaticMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PrivateAndStaticMethodCollisionTest.java
@@ -22,7 +22,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addHorizontallyMergedClassesInspectorIf(
enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class))
.enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ReferencedInAnnotationTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ReferencedInAnnotationTest.java
index 620f948..385d782 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ReferencedInAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ReferencedInAnnotationTest.java
@@ -38,7 +38,8 @@
.addKeepMainRule(TestClass.class)
.addKeepClassAndMembersRules(Annotation.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addKeepRuntimeVisibleAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapFieldTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapFieldTest.java
index 33c8a85..168d6ee 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapFieldTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapFieldTest.java
@@ -24,7 +24,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapMethodTest.java
index a531860..c640ffc 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapMethodTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/RemapMethodTest.java
@@ -24,7 +24,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderParentTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderParentTest.java
index 4e89fb8..5eab9c9 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderParentTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderParentTest.java
@@ -38,7 +38,8 @@
Origin.unknown()))
.enableNoVerticalClassMergingAnnotations()
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
.assertSuccess()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderTest.java
index ee6dc18..f9ae4bd 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ServiceLoaderTest.java
@@ -36,7 +36,8 @@
"META-INF/services/" + A.class.getTypeName(),
Origin.unknown()))
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
.assertSuccess()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndInterfaceMethodCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndInterfaceMethodCollisionTest.java
index ebbfd86..e76dd447 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndInterfaceMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndInterfaceMethodCollisionTest.java
@@ -25,7 +25,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addHorizontallyMergedClassesInspector(
HorizontallyMergedClassesInspector::assertNoClassesMerged)
.enableInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndVirtualMethodCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndVirtualMethodCollisionTest.java
index edca180..35a15e5 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndVirtualMethodCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/StaticAndVirtualMethodCollisionTest.java
@@ -23,7 +23,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.addHorizontallyMergedClassesInspectorIf(
enableHorizontalClassMerging, inspector -> inspector.assertMergedInto(B.class, A.class))
.enableInliningAnnotations()
@@ -36,10 +37,10 @@
static class Main {
public static void main(String[] args) {
- new A().foo();
+ A.foo();
new A().bar();
new B().foo();
- new B().bar();
+ B.bar();
}
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java
index 119913b..ecbd84b 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java
@@ -25,7 +25,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/SynchronizedClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/SynchronizedClassesTest.java
index e5c77a3..6f458b7 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/SynchronizedClassesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/SynchronizedClassesTest.java
@@ -26,7 +26,7 @@
.addKeepMainRule(Main.class)
.addOptionsModification(
options -> {
- options.enableHorizontalClassMerging = enableHorizontalClassMerging;
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging);
})
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/SyntheticConstructorArgumentsMerged.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/SyntheticConstructorArgumentsMerged.java
index 59ea0b2..6567764 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/SyntheticConstructorArgumentsMerged.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/SyntheticConstructorArgumentsMerged.java
@@ -26,7 +26,7 @@
.addKeepMainRule(Main.class)
.addOptionsModification(
options -> {
- options.enableHorizontalClassMerging = enableHorizontalClassMerging;
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging);
})
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerCollisionTest.java
index b603f66..97e41db 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerCollisionTest.java
@@ -26,7 +26,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerConstructorCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerConstructorCollisionTest.java
index a5c5555..c7a7d9c 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerConstructorCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerConstructorCollisionTest.java
@@ -30,7 +30,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoHorizontalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceCollisionTest.java
index f1301a0..946e113 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceCollisionTest.java
@@ -36,7 +36,8 @@
.addKeepMainRule(Main.class)
.noMinification()
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceFixedCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceFixedCollisionTest.java
index 2f6895a..1d3290a 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceFixedCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceFixedCollisionTest.java
@@ -38,7 +38,8 @@
.addKeepMainRule(Main.class)
.noMinification()
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceImplementedByParentTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceImplementedByParentTest.java
index b6a320c..afee32c 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceImplementedByParentTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerInterfaceImplementedByParentTest.java
@@ -34,7 +34,8 @@
.addKeepMainRule(Main.class)
.noMinification()
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerSubClassCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerSubClassCollisionTest.java
index aad0efa..b68f291 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerSubClassCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/TreeFixerSubClassCollisionTest.java
@@ -29,7 +29,8 @@
.addKeepMainRule(Main.class)
.noMinification()
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticalMergingPreoptimizedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticalMergingPreoptimizedTest.java
index 7731d5e..b1c0b4a 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticalMergingPreoptimizedTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticalMergingPreoptimizedTest.java
@@ -28,7 +28,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoHorizontalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByCheckCastTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByCheckCastTest.java
index 9ecbf5a..366800a 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByCheckCastTest.java
@@ -23,7 +23,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByInstanceOfTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByInstanceOfTest.java
index bba42bb..c8ad21d 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassDistinguishedByInstanceOfTest.java
@@ -23,7 +23,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassTest.java
index e40ff51..a40b387 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VerticallyMergedClassTest.java
@@ -27,7 +27,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableNoHorizontalClassMergingAnnotations()
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfFinalAndNonFinalMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfFinalAndNonFinalMethodTest.java
index f9eff69..6399f3e 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfFinalAndNonFinalMethodTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfFinalAndNonFinalMethodTest.java
@@ -28,7 +28,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(TestClass.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfPublicizedMethodsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfPublicizedMethodsTest.java
index 8178138..5e23840 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfPublicizedMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodMergingOfPublicizedMethodsTest.java
@@ -25,7 +25,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(TestClass.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.allowAccessModification()
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/NotOverlappingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/NotOverlappingTest.java
index 8742e67..e405aa9 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/NotOverlappingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/NotOverlappingTest.java
@@ -23,7 +23,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java
index 87f4dc3..e456600 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideAbstractMethodWithDefaultTest.java
@@ -25,7 +25,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultMethodTest.java
index dd8183d..0e3a098 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultMethodTest.java
@@ -26,7 +26,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultOnSuperMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultOnSuperMethodTest.java
index bd41f8f..fa2dcb2 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultOnSuperMethodTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideDefaultOnSuperMethodTest.java
@@ -27,7 +27,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNoUnusedInterfaceRemovalAnnotations()
.enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideMergeAbsentTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideMergeAbsentTest.java
index fe0bc23..526aa00 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideMergeAbsentTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideMergeAbsentTest.java
@@ -25,7 +25,8 @@
.addInnerClasses(getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideParentCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideParentCollisionTest.java
index 94b643a..639cf19 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideParentCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/OverrideParentCollisionTest.java
@@ -27,7 +27,8 @@
.addInnerClasses(this.getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/SuperMethodMergedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/SuperMethodMergedTest.java
index 228223f..44973bc 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/SuperMethodMergedTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/dispatch/SuperMethodMergedTest.java
@@ -26,7 +26,8 @@
.addInnerClasses(this.getClass())
.addKeepMainRule(Main.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
index 2fb36cd..8dc4e01 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerTest.java
@@ -253,6 +253,7 @@
testForR8(parameters.getBackend())
.addKeepRules(getProguardConfig(EXAMPLE_KEEP))
.addOptionsModification(this::configure)
+ .addOptionsModification(options -> options.enableValuePropagation = false)
.addOptionsModification(
options ->
options.testing.validInliningReasons = ImmutableSet.of(Reason.FORCE))
@@ -276,10 +277,11 @@
assertThat(clazzSubject.field("java.lang.String", "name" + suffix), isPresent());
assertThat(clazzSubject.field("java.lang.String", "name" + suffix + "2"), isPresent());
- // The direct method "constructor$classmerging$ConflictInGeneratedNameTest$A" is processed after
- // the method "<init>" is renamed to exactly that name. Therefore the conflict should have been
- // resolved by appending [suffix] to it.
- assertThat(clazzSubject.method("void", "constructor" + suffix + suffix, EMPTY), isPresent());
+ // The direct method "$r8$constructor$classmerging$ConflictInGeneratedNameTest$A" is processed
+ // after the method "<init>" is renamed to exactly that name. Therefore the conflict should have
+ // been resolved by appending [suffix] to it.
+ assertThat(
+ clazzSubject.method("void", "$r8$constructor" + suffix + suffix, EMPTY), isPresent());
// There should be two foo's.
assertThat(clazzSubject.method("void", "foo", EMPTY), isPresent());
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 ae1c81c..deb97d8 100644
--- a/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
+++ b/src/test/java/com/android/tools/r8/debug/KotlinStdLibCompilationTest.java
@@ -3,16 +3,18 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.debug;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
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.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -22,21 +24,25 @@
public class KotlinStdLibCompilationTest extends TestBase {
private final TestParameters parameters;
+ private final KotlinCompiler kotlinc;
- @Parameters(name = "{0}")
- public static TestParametersCollection setup() {
- return TestParametersBuilder.builder().withAllRuntimes().withAllApiLevels().build();
+ @Parameters(name = "{0}, kotlinc: {1}")
+ public static List<Object[]> setup() {
+ return buildParameters(
+ TestParametersBuilder.builder().withAllRuntimes().withAllApiLevels().build(),
+ getKotlinCompilers());
}
- public KotlinStdLibCompilationTest(TestParameters parameters) {
+ public KotlinStdLibCompilationTest(TestParameters parameters, KotlinCompiler kotlinc) {
this.parameters = parameters;
+ this.kotlinc = kotlinc;
}
@Test
public void testD8() throws CompilationFailedException {
assumeTrue(parameters.isDexRuntime());
testForD8()
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.setMinApi(parameters.getApiLevel())
.compileWithExpectedDiagnostics(TestDiagnosticMessages::assertNoMessages);
}
@@ -44,7 +50,7 @@
@Test
public void testR8() throws CompilationFailedException {
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.noMinification()
.noTreeShaking()
.addKeepAllAttributes()
diff --git a/src/test/java/com/android/tools/r8/debuginfo/CannonicalizeWithInline.java b/src/test/java/com/android/tools/r8/debuginfo/CanonicalizeWithInline.java
similarity index 61%
rename from src/test/java/com/android/tools/r8/debuginfo/CannonicalizeWithInline.java
rename to src/test/java/com/android/tools/r8/debuginfo/CanonicalizeWithInline.java
index ff58696..395f29f 100644
--- a/src/test/java/com/android/tools/r8/debuginfo/CannonicalizeWithInline.java
+++ b/src/test/java/com/android/tools/r8/debuginfo/CanonicalizeWithInline.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.debuginfo;
+import com.android.tools.r8.AssumeMayHaveSideEffects;
+import com.android.tools.r8.NeverInline;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
@@ -15,7 +17,7 @@
import org.junit.Assert;
import org.junit.Test;
-public class CannonicalizeWithInline extends TestBase {
+public class CanonicalizeWithInline extends TestBase {
private int getNumberOfDebugInfos(Path file) throws IOException {
DexSection[] dexSections = DexParser.parseMapFrom(file);
@@ -28,25 +30,23 @@
}
@Test
- public void testCannonicalize() throws Exception {
- Class clazzA = ClassA.class;
- Class clazzB = ClassB.class;
+ public void testCanonicalize() throws Exception {
+ Class<?> clazzA = ClassA.class;
+ Class<?> clazzB = ClassB.class;
- R8TestCompileResult result = testForR8(Backend.DEX)
- .addProgramClasses(clazzA, clazzB)
- .addKeepRules(
- "-keepattributes SourceFile,LineNumberTable",
- "-keep class ** {\n" +
- "public void call(int);\n" +
- "}"
- )
- // String concatenation optimization will remove dead builders in foobar.
- .addOptionsModification(o -> o.enableStringConcatenationOptimization = false)
- .compile();
+ R8TestCompileResult result =
+ testForR8(Backend.DEX)
+ .addProgramClasses(clazzA, clazzB)
+ .addKeepRules(
+ "-keepattributes SourceFile,LineNumberTable",
+ "-keep class ** {\n" + "public void call(int);\n" + "}")
+ .enableInliningAnnotations()
+ .enableSideEffectAnnotations()
+ .compile();
Path classesPath = temp.getRoot().toPath();
result.app.write(classesPath, OutputMode.DexIndexed);
- int numberOfDebugInfos = getNumberOfDebugInfos(
- Paths.get(temp.getRoot().getCanonicalPath(), "classes.dex"));
+ int numberOfDebugInfos =
+ getNumberOfDebugInfos(Paths.get(temp.getRoot().getCanonicalPath(), "classes.dex"));
Assert.assertEquals(1, numberOfDebugInfos);
}
@@ -57,11 +57,17 @@
public static class ClassA {
public void call(int a) {
- foobar(a);
+ foobar(a);
}
private String foobar(int a) {
- String s = "aFoobar" + a;
+ return doSomething(a);
+ }
+
+ @AssumeMayHaveSideEffects
+ @NeverInline
+ private String doSomething(int a) {
+ String s = "bFoobar" + a;
return s;
}
}
@@ -73,6 +79,12 @@
}
private String foobar(int a) {
+ return doSomething(a);
+ }
+
+ @AssumeMayHaveSideEffects
+ @NeverInline
+ private String doSomething(int a) {
String s = "bFoobar" + a;
return s;
}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ImplementedInterfacesTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ImplementedInterfacesTest.java
new file mode 100644
index 0000000..b5ab3b5
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/ImplementedInterfacesTest.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.desugaredlibrary;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static junit.framework.TestCase.assertFalse;
+import static junit.framework.TestCase.assertTrue;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+import java.util.Spliterator;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class ImplementedInterfacesTest extends DesugaredLibraryTestBase {
+
+ private final TestParameters parameters;
+ private final boolean canUseDefaultAndStaticInterfaceMethods;
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build());
+ }
+
+ public ImplementedInterfacesTest(TestParameters parameters) {
+ this.parameters = parameters;
+ this.canUseDefaultAndStaticInterfaceMethods =
+ parameters
+ .getApiLevel()
+ .isGreaterThanOrEqualTo(apiLevelWithDefaultInterfaceMethodsSupport());
+ }
+
+ private String desugaredJavaTypeNameFor(Class<?> clazz) {
+ return clazz.getTypeName().replace("java.", "j$.");
+ }
+
+ private void checkInterfaces(CodeInspector inspector) {
+ ClassSubject clazz = inspector.clazz(MultipleInterfaces.class);
+ assertThat(clazz, isPresent());
+ assertTrue(clazz.isImplementing(Serializable.class));
+ assertTrue(clazz.isImplementing(Set.class));
+ assertTrue(clazz.isImplementing(List.class));
+ assertFalse(clazz.isImplementing(Collection.class));
+ assertFalse(clazz.isImplementing(Iterable.class));
+ if (!canUseDefaultAndStaticInterfaceMethods) {
+ assertFalse(clazz.isImplementing(desugaredJavaTypeNameFor(Serializable.class)));
+ assertTrue(clazz.isImplementing(desugaredJavaTypeNameFor(Set.class)));
+ assertTrue(clazz.isImplementing(desugaredJavaTypeNameFor(List.class)));
+ assertFalse(clazz.isImplementing(desugaredJavaTypeNameFor(Collection.class)));
+ assertFalse(clazz.isImplementing(desugaredJavaTypeNameFor(Iterable.class)));
+ }
+ }
+
+ @Test
+ public void testInterfaces() throws Exception {
+ KeepRuleConsumer keepRuleConsumer = createKeepRuleConsumer(parameters);
+ testForD8(parameters.getBackend())
+ .addInnerClasses(ImplementedInterfacesTest.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
+ .compile()
+ .inspect(this::checkInterfaces);
+ }
+
+ abstract static class MultipleInterfaces<T> implements List<T>, Serializable, Set<T> {
+
+ // Disambiguate between default methods List.spliterator() and Set.spliterator()
+ @Override
+ public Spliterator<T> spliterator() {
+ return Set.super.spliterator();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
index ebf503a..89748a7 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/kotlin/KotlinMetadataTest.java
@@ -4,7 +4,8 @@
package com.android.tools.r8.desugar.desugaredlibrary.kotlin;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.KotlinTestBase.getCompileMemoizer;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
@@ -15,6 +16,8 @@
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestBase.KotlinCompileMemoizer;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.R8TestRunResult;
@@ -24,20 +27,15 @@
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
import com.android.tools.r8.kotlin.KotlinMetadataWriter;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
-import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.io.File;
-import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import kotlinx.metadata.jvm.KotlinClassMetadata;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -50,50 +48,44 @@
private final TestParameters parameters;
private final boolean shrinkDesugaredLibrary;
private final KotlinTargetVersion targetVersion;
+ private final KotlinCompiler kotlinCompiler;
private static final String EXPECTED_OUTPUT = "Wuhuu, my special day is: 1997-8-29-2-14";
- @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}, target: {2}")
+ @Parameters(name = "{1}, shrinkDesugaredLibrary: {0}, target: {2}, kotlinc: {3}")
public static List<Object[]> data() {
return buildParameters(
BooleanUtils.values(),
getTestParameters().withAllRuntimesAndApiLevels().build(),
- KotlinTargetVersion.values());
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public KotlinMetadataTest(
boolean shrinkDesugaredLibrary,
TestParameters parameters,
- KotlinTargetVersion targetVersion) {
+ KotlinTargetVersion targetVersion,
+ KotlinCompiler kotlinCompiler) {
this.shrinkDesugaredLibrary = shrinkDesugaredLibrary;
this.parameters = parameters;
this.targetVersion = targetVersion;
+ this.kotlinCompiler = kotlinCompiler;
}
- private static Map<KotlinTargetVersion, Path> compiledJars = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- compiledJars.put(
- targetVersion,
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- Paths.get(
- ToolHelper.TESTS_DIR,
- "java",
- DescriptorUtils.getBinaryNameFromJavaType(PKG),
- "Main" + FileUtils.KT_EXTENSION))
- .compile());
- }
- }
+ private static KotlinCompileMemoizer compiledJars =
+ getCompileMemoizer(
+ Paths.get(
+ ToolHelper.TESTS_DIR,
+ "java",
+ DescriptorUtils.getBinaryNameFromJavaType(PKG),
+ "Main" + FileUtils.KT_EXTENSION));
@Test
public void testCf() throws Exception {
assumeTrue(parameters.getRuntime().isCf());
testForRuntime(parameters)
- .addProgramFiles(compiledJars.get(targetVersion))
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(ToolHelper.getKotlinReflectJar())
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinCompiler, targetVersion))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinCompiler))
+ .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinCompiler))
.run(parameters.getRuntime(), PKG + ".MainKt")
.assertSuccessWithOutputLines(EXPECTED_OUTPUT);
}
@@ -105,9 +97,9 @@
final File output = temp.newFile("output.zip");
final D8TestRunResult d8TestRunResult =
testForD8()
- .addProgramFiles(compiledJars.get(targetVersion))
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(ToolHelper.getKotlinReflectJar())
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinCompiler, targetVersion))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinCompiler))
+ .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinCompiler))
.setProgramConsumer(new ArchiveConsumer(output.toPath(), true))
.setMinApi(parameters.getApiLevel())
.enableCoreLibraryDesugaring(parameters.getApiLevel(), keepRuleConsumer)
@@ -134,9 +126,9 @@
boolean desugarLibrary = parameters.isDexRuntime() && requiresAnyCoreLibDesugaring(parameters);
final R8FullTestBuilder testBuilder =
testForR8(parameters.getBackend())
- .addProgramFiles(compiledJars.get(targetVersion))
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(ToolHelper.getKotlinReflectJar())
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinCompiler, targetVersion))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinCompiler))
+ .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinCompiler))
.addKeepMainRule(PKG + ".MainKt")
.addKeepAllClassesRule()
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
diff --git a/src/test/java/com/android/tools/r8/desugar/records/RecordsAttributeTest.java b/src/test/java/com/android/tools/r8/desugar/records/RecordsAttributeTest.java
new file mode 100644
index 0000000..831c426
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/records/RecordsAttributeTest.java
@@ -0,0 +1,87 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.records;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeFalse;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.examples.jdk15.Records;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RecordsAttributeTest extends TestBase {
+
+ private final Backend backend;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk15).
+ return buildParameters(
+ getTestParameters().withCustomRuntime(CfRuntime.getCheckedInJdk15()).build(),
+ Backend.values());
+ }
+
+ public RecordsAttributeTest(TestParameters parameters, Backend backend) {
+ this.parameters = parameters;
+ this.backend = backend;
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeFalse(parameters.isNoneRuntime());
+ assumeTrue(backend == Backend.CF);
+ testForJvm()
+ .addRunClasspathFiles(Records.jar())
+ .addVmArguments("--enable-preview")
+ .run(parameters.getRuntime(), Records.Main.typeName())
+ .assertSuccessWithOutputLines("Jane Doe", "42");
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assertThrows(
+ CompilationFailedException.class,
+ () -> {
+ testForD8(backend)
+ .addProgramClassFileData(Records.Main.bytes(), Records.Main$Person.bytes())
+ .setMinApi(AndroidApiLevel.B)
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics.assertErrorThatMatches(
+ diagnosticMessage(containsString("Records are not supported")));
+ });
+ });
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ assertThrows(
+ CompilationFailedException.class,
+ () -> {
+ testForR8(backend)
+ .addProgramClassFileData(Records.Main.bytes(), Records.Main$Person.bytes())
+ .setMinApi(AndroidApiLevel.B)
+ .addKeepMainRule(Records.Main.typeName())
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics.assertErrorThatMatches(
+ diagnosticMessage(containsString("Records are not supported")));
+ });
+ });
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java
new file mode 100644
index 0000000..48b29e7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/sealed/SealedAttributeTest.java
@@ -0,0 +1,83 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.desugar.sealed;
+
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThrows;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime;
+import com.android.tools.r8.examples.jdk15.Sealed;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class SealedAttributeTest extends TestBase {
+
+ private final Backend backend;
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ // TODO(b/174431251): This should be replaced with .withCfRuntimes(start = jdk15).
+ return buildParameters(
+ getTestParameters().withCustomRuntime(TestRuntime.getCheckedInJdk15()).build(),
+ Backend.values());
+ }
+
+ public SealedAttributeTest(TestParameters parameters, Backend backend) {
+ this.backend = backend;
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(backend == Backend.CF);
+ testForJvm()
+ .addRunClasspathFiles(Sealed.jar())
+ .addVmArguments("--enable-preview")
+ .run(TestRuntime.getCheckedInJdk15(), Sealed.Main.typeName())
+ .assertSuccessWithOutputLines("R8 compiler", "D8 compiler");
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assertThrows(
+ CompilationFailedException.class,
+ () -> {
+ testForD8(backend)
+ .addProgramFiles(Sealed.jar())
+ .setMinApi(AndroidApiLevel.B)
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics.assertErrorThatMatches(
+ diagnosticMessage(containsString("Sealed classes are not supported")));
+ });
+ });
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ assertThrows(
+ CompilationFailedException.class,
+ () -> {
+ testForR8(backend)
+ .addProgramFiles(Sealed.jar())
+ .setMinApi(AndroidApiLevel.B)
+ .addKeepMainRule(Sealed.Main.typeName())
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics.assertErrorThatMatches(
+ diagnosticMessage(containsString("Sealed classes are not supported")));
+ });
+ });
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/EnumWithNonDefaultForwardingConstructorTest.java b/src/test/java/com/android/tools/r8/enumunboxing/EnumWithNonDefaultForwardingConstructorTest.java
index 92b0b54..926a7b0 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/EnumWithNonDefaultForwardingConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/EnumWithNonDefaultForwardingConstructorTest.java
@@ -54,8 +54,7 @@
.setMinApi(parameters.getApiLevel())
.compile()
.run(parameters.getRuntime(), TestClass.class)
- // TODO(b/160939354): Should succeed with 42.
- .assertSuccessWithOutputLines(enableEnumUnboxing ? "0" : "42");
+ .assertSuccessWithOutputLines("42");
}
private void addProgramClasses(TestBuilder<?, ?> builder) throws Exception {
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/kotlin/SimpleKotlinEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/kotlin/SimpleKotlinEnumUnboxingTest.java
index 1bb9c1e..a4f280c 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/kotlin/SimpleKotlinEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/kotlin/SimpleKotlinEnumUnboxingTest.java
@@ -4,21 +4,20 @@
package com.android.tools.r8.enumunboxing.kotlin;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.KotlinTestBase.getCompileMemoizer;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestBase.KotlinCompileMemoizer;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.enumunboxing.EnumUnboxingTestBase;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.DescriptorUtils;
-import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -31,51 +30,45 @@
private final boolean enumValueOptimization;
private final EnumKeepRules enumKeepRules;
private final KotlinTargetVersion targetVersion;
+ private final KotlinCompiler kotlinCompiler;
private static final String PKG = SimpleKotlinEnumUnboxingTest.class.getPackage().getName();
- private static Map<KotlinTargetVersion, Path> jars = new HashMap<>();
+ private static final KotlinCompileMemoizer jars =
+ getCompileMemoizer(
+ Paths.get(
+ ToolHelper.TESTS_DIR,
+ "java",
+ DescriptorUtils.getBinaryNameFromJavaType(PKG),
+ "Main.kt"));
- @Parameters(name = "{0}, valueOpt: {1}, keep: {2}, kotlin targetVersion: {3}")
+ @Parameters(name = "{0}, valueOpt: {1}, keep: {2}, kotlin targetVersion: {3}, kotlinc: {4}")
public static List<Object[]> enumUnboxingTestParameters() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
BooleanUtils.values(),
getAllEnumKeepRules(),
- KotlinTargetVersion.values());
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public SimpleKotlinEnumUnboxingTest(
TestParameters parameters,
boolean enumValueOptimization,
EnumKeepRules enumKeepRules,
- KotlinTargetVersion targetVersion) {
+ KotlinTargetVersion targetVersion,
+ KotlinCompiler kotlinCompiler) {
this.parameters = parameters;
this.enumValueOptimization = enumValueOptimization;
this.enumKeepRules = enumKeepRules;
this.targetVersion = targetVersion;
- }
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- jars.put(
- targetVersion,
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- Paths.get(
- ToolHelper.TESTS_DIR,
- "java",
- DescriptorUtils.getBinaryNameFromJavaType(PKG),
- "Main.kt"))
- .compile());
- }
+ this.kotlinCompiler = kotlinCompiler;
}
@Test
public void testEnumUnboxing() throws Exception {
assumeTrue(parameters.isDexRuntime());
testForR8(parameters.getBackend())
- .addProgramFiles(jars.get(targetVersion))
+ .addProgramFiles(jars.getForConfiguration(kotlinCompiler, targetVersion))
.addKeepMainRule(PKG + ".MainKt")
.addKeepRules(enumKeepRules.getKeepRules())
.addKeepRuntimeVisibleAnnotations()
diff --git a/src/test/java/com/android/tools/r8/examples/JavaExampleClassProxy.java b/src/test/java/com/android/tools/r8/examples/JavaExampleClassProxy.java
new file mode 100644
index 0000000..6bbbfd1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/JavaExampleClassProxy.java
@@ -0,0 +1,53 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.examples;
+
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.google.common.io.ByteStreams;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.zip.ZipFile;
+
+public class JavaExampleClassProxy {
+
+ private final String examplesFolder;
+ private final String binaryName;
+
+ public JavaExampleClassProxy(String examples, String binaryName) {
+ this.examplesFolder = examples;
+ this.binaryName = binaryName;
+ }
+
+ public static Path examplesJar(String examplesFolder) {
+ return Paths.get(ToolHelper.BUILD_DIR, "test", examplesFolder + ".jar");
+ }
+
+ public byte[] bytes() {
+ Path examplePath = examplesJar(examplesFolder);
+ if (!Files.exists(examplePath)) {
+ throw new RuntimeException(
+ "Could not find path "
+ + examplePath
+ + ". Build "
+ + examplesFolder
+ + " by running tools/gradle.py build"
+ + StringUtils.capitalize(examplesFolder));
+ }
+ try (ZipFile zipFile = new ZipFile(examplePath.toFile())) {
+ return ByteStreams.toByteArray(
+ zipFile.getInputStream(zipFile.getEntry(binaryName + ".class")));
+ } catch (IOException e) {
+ throw new RuntimeException("Could not read zip-entry from " + examplePath.toString(), e);
+ }
+ }
+
+ public String typeName() {
+ return DescriptorUtils.getJavaTypeFromBinaryName(binaryName);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/examples/jdk15/Records.java b/src/test/java/com/android/tools/r8/examples/jdk15/Records.java
new file mode 100644
index 0000000..9eafc56
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/jdk15/Records.java
@@ -0,0 +1,22 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.examples.jdk15;
+
+import com.android.tools.r8.examples.JavaExampleClassProxy;
+import java.nio.file.Path;
+
+public class Records {
+
+ private static final String EXAMPLE_FILE = "examplesJava15/records";
+
+ public static final JavaExampleClassProxy Main =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "records/Main");
+ public static final JavaExampleClassProxy Main$Person =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "records/Main$Person");
+
+ public static Path jar() {
+ return JavaExampleClassProxy.examplesJar(EXAMPLE_FILE);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/examples/jdk15/Sealed.java b/src/test/java/com/android/tools/r8/examples/jdk15/Sealed.java
new file mode 100644
index 0000000..1450ee8
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/examples/jdk15/Sealed.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.examples.jdk15;
+
+import com.android.tools.r8.examples.JavaExampleClassProxy;
+import java.nio.file.Path;
+
+public class Sealed {
+
+ private static final String EXAMPLE_FILE = "examplesJava15/sealed";
+
+ public static final JavaExampleClassProxy Compiler =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "sealed/Compiler");
+ public static final JavaExampleClassProxy R8Compiler =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "sealed/R8Compiler");
+ public static final JavaExampleClassProxy D8Compiler =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "sealed/D8Compiler");
+ public static final JavaExampleClassProxy Main =
+ new JavaExampleClassProxy(EXAMPLE_FILE, "sealed/Main");
+
+ public static Path jar() {
+ return JavaExampleClassProxy.examplesJar(EXAMPLE_FILE);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/graph/DexTypeTest.java b/src/test/java/com/android/tools/r8/graph/DexTypeTest.java
index 6b2d73e..82ee9e8 100644
--- a/src/test/java/com/android/tools/r8/graph/DexTypeTest.java
+++ b/src/test/java/com/android/tools/r8/graph/DexTypeTest.java
@@ -28,7 +28,7 @@
new ApplicationReader(
AndroidApp.builder()
.addLibraryFiles(ToolHelper.getDefaultAndroidJar())
- .addLibraryFiles(ToolHelper.getKotlinStdlibJar())
+ .addLibraryFiles(ToolHelper.getKotlinStdlibJar(ToolHelper.getKotlinC_1_3_72()))
.build(),
options,
Timing.empty())
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/DevirtualizeWithCatchHandlersTest.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/DevirtualizeWithCatchHandlersTest.java
new file mode 100644
index 0000000..a126f0f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/DevirtualizeWithCatchHandlersTest.java
@@ -0,0 +1,88 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.devirtualize;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class DevirtualizeWithCatchHandlersTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return TestBase.getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public DevirtualizeWithCatchHandlersTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepRules(
+ // Disable uninstantiated type optimization for m().
+ "-keepclassmembers class " + Uninstantiated.class.getTypeName() + " {",
+ " " + Uninstantiated.class.getTypeName() + " get();",
+ "}")
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ try {
+ test();
+ } catch (Exception e) {
+ System.out.println("Dead!");
+ }
+ }
+
+ static synchronized void test() {
+ I which = System.currentTimeMillis() > 0 ? new A() : Uninstantiated.get();
+ which.m();
+ }
+ }
+
+ interface I {
+
+ void m();
+ }
+
+ static class A implements I {
+
+ @NeverInline
+ @Override
+ public void m() {
+ System.out.println("A");
+ }
+ }
+
+ static class Uninstantiated implements I {
+
+ static Uninstantiated get() {
+ return null;
+ }
+
+ @Override
+ public void m() {
+ throw new RuntimeException();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PrivateOverridePublicizerDevirtualizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PrivateOverridePublicizerDevirtualizerTest.java
index bef0cd5..86739dc 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PrivateOverridePublicizerDevirtualizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/PrivateOverridePublicizerDevirtualizerTest.java
@@ -5,13 +5,11 @@
package com.android.tools.r8.ir.optimize.devirtualize;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoVerticalClassMerging;
-import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -48,33 +46,25 @@
@Test
public void testR8() throws Exception {
- R8TestRunResult runResult =
- testForR8(parameters.getBackend())
- .addInnerClasses(PrivateOverridePublicizerDevirtualizerTest.class)
- .enableInliningAnnotations()
- .enableNoVerticalClassMergingAnnotations()
- .enableNeverClassInliningAnnotations()
- .addKeepMainRule(Main.class)
- .allowAccessModification()
- .noMinification()
- .setMinApi(parameters.getApiLevel())
- .compile()
- .inspect(
- inspector -> {
- ClassSubject classA = inspector.clazz(A.class);
- assertThat(classA, isPresent());
- MethodSubject fooA = classA.uniqueMethodWithName("foo");
- // TODO(b/173812804): This should not be removed.
- assertThat(fooA, not(isPresent()));
- })
- .run(parameters.getRuntime(), Main.class);
- if (parameters.isDexRuntime()) {
- // TODO(b/173812804): This should not fail verification
- runResult.assertFailureWithErrorThatThrows(VerifyError.class);
- } else {
- // TODO(b/173812804): This should have been A::foo, B::foo.
- runResult.assertSuccessWithOutputLines("B::foo", "B::foo");
- }
+ testForR8(parameters.getBackend())
+ .addInnerClasses(PrivateOverridePublicizerDevirtualizerTest.class)
+ .enableInliningAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .addKeepMainRule(Main.class)
+ .allowAccessModification()
+ .noMinification()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject classA = inspector.clazz(A.class);
+ assertThat(classA, isPresent());
+ MethodSubject fooA = classA.uniqueMethodWithName("foo");
+ assertThat(fooA, isPresent());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
}
@NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynthesizedLambdaClass.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynthesizedLambdaClass.java
index 117a18c..1bd8db6 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynthesizedLambdaClass.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineSynthesizedLambdaClass.java
@@ -23,7 +23,7 @@
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters().withDexRuntimes().build();
+ return getTestParameters().withDexRuntimes().withAllApiLevels().build();
}
public InlineSynthesizedLambdaClass(TestParameters parameters) {
@@ -42,7 +42,7 @@
.addKeepMainRule(Lambda.class)
.allowAccessModification()
.noMinification()
- .setMinApi(parameters.getRuntime())
+ .setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Lambda.class)
.assertSuccessWithOutput(javaOutput)
.inspector();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInitClassPositionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInitClassPositionTest.java
new file mode 100644
index 0000000..1dc11c0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInitClassPositionTest.java
@@ -0,0 +1,80 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.inliner;
+
+import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.naming.retrace.StackTrace;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class SyntheticInitClassPositionTest extends TestBase {
+
+ private final TestParameters parameters;
+ private StackTrace expectedStackTrace;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return TestBase.getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Before
+ public void setup() throws Exception {
+ // Get the expected stack trace by running on the JVM.
+ expectedStackTrace =
+ testForJvm()
+ .addTestClasspath()
+ .run(CfRuntime.getSystemRuntime(), Main.class)
+ .assertFailure()
+ .map(StackTrace::extractFromJvm);
+ }
+
+ public SyntheticInitClassPositionTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepAttributeLineNumberTable()
+ .addKeepAttributeSourceFile()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(ExceptionInInitializerError.class)
+ .inspectStackTrace(stackTrace -> assertThat(stackTrace, isSame(expectedStackTrace)));
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ A.m();
+ }
+ }
+
+ static class A {
+
+ static {
+ if (true) {
+ throw new RuntimeException();
+ }
+ }
+
+ static void m() {
+ System.out.println("Hello world!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInlineNullCheckPositionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInlineNullCheckPositionTest.java
new file mode 100644
index 0000000..4eadc56
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/SyntheticInlineNullCheckPositionTest.java
@@ -0,0 +1,99 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.inliner;
+
+import static com.android.tools.r8.naming.retrace.StackTrace.isSame;
+import static com.android.tools.r8.naming.retrace.StackTrace.isSameExceptForSpecificLineNumber;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.naming.retrace.StackTrace;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import java.util.Objects;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class SyntheticInlineNullCheckPositionTest extends TestBase {
+
+ private static final StackTraceLine REQUIRE_NON_NULL_LINE =
+ StackTraceLine.builder()
+ .setClassName(Objects.class.getTypeName())
+ .setMethodName("requireNonNull")
+ .setFileName("Objects.java")
+ .build();
+
+ private final TestParameters parameters;
+ private StackTrace expectedStackTraceWithGetClass;
+ private StackTrace expectedStackTraceWithRequireNonNull;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return TestBase.getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ @Before
+ public void setup() throws Exception {
+ // Get the expected stack trace by running on the JVM.
+ StackTrace actualStackTrace =
+ testForJvm()
+ .addTestClasspath()
+ .run(CfRuntime.getSystemRuntime(), Main.class)
+ .assertFailure()
+ .map(StackTrace::extractFromJvm);
+ expectedStackTraceWithGetClass = actualStackTrace;
+ expectedStackTraceWithRequireNonNull =
+ StackTrace.builder().add(REQUIRE_NON_NULL_LINE).add(actualStackTrace).build();
+ }
+
+ public SyntheticInlineNullCheckPositionTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepAttributeLineNumberTable()
+ .addKeepAttributeSourceFile()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertFailureWithErrorThatThrows(NullPointerException.class)
+ .inspectStackTrace(
+ stackTrace -> {
+ if (canUseRequireNonNull(parameters)) {
+ assertThat(
+ stackTrace,
+ isSameExceptForSpecificLineNumber(
+ expectedStackTraceWithRequireNonNull, REQUIRE_NON_NULL_LINE));
+ } else {
+ assertThat(stackTrace, isSame(expectedStackTraceWithGetClass));
+ }
+ });
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ A nullable = System.currentTimeMillis() < 0 ? new A() : null;
+ nullable.m();
+ }
+ }
+
+ static class A {
+
+ void m() {
+ System.out.println("Hello world!");
+ }
+ }
+}
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 8bdea50..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
@@ -43,6 +43,8 @@
.enableInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
.addOptionsModification(options -> options.enableClassInlining = false)
+ // TODO(b/173398086): Horizontal class merging breaks uniqueMethodWithName().
+ .noMinification()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderFromCharSequenceWithAppendObjectTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderFromCharSequenceWithAppendObjectTest.java
new file mode 100644
index 0000000..8f1f58b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderFromCharSequenceWithAppendObjectTest.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.string;
+
+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 org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class UnusedStringBuilderFromCharSequenceWithAppendObjectTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public UnusedStringBuilderFromCharSequenceWithAppendObjectTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLinesIf(
+ parameters.isCfRuntime()
+ || parameters.getDexRuntimeVersion().isNewerThanOrEqual(Version.V7_0_0),
+ "CustomCharSequence.length()",
+ "CustomCharSequence.length()",
+ "CustomCharSequence.length()",
+ "CustomCharSequence.charAt(0)")
+ .assertSuccessWithOutputLinesIf(
+ parameters.isDexRuntime()
+ && parameters.getDexRuntimeVersion().isOlderThan(Version.V7_0_0),
+ "CustomCharSequence.toString()");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ new StringBuilder(new CustomCharSequence());
+ }
+ }
+
+ static class CustomCharSequence implements CharSequence {
+
+ @Override
+ public int length() {
+ System.out.println("CustomCharSequence.length()");
+ return 1;
+ }
+
+ @Override
+ public char charAt(int i) {
+ if (i != 0) {
+ throw new RuntimeException();
+ }
+ System.out.println("CustomCharSequence.charAt(0)");
+ return 'A';
+ }
+
+ @Override
+ public CharSequence subSequence(int i, int i1) {
+ throw new RuntimeException();
+ }
+
+ @Override
+ public String toString() {
+ System.out.println("CustomCharSequence.toString()");
+ return "A";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderWithAppendDefinitelyNullObjectTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderWithAppendDefinitelyNullObjectTest.java
new file mode 100644
index 0000000..f5f615d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderWithAppendDefinitelyNullObjectTest.java
@@ -0,0 +1,58 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.string;
+
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.instantiatesClass;
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.invokesMethodWithName;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class UnusedStringBuilderWithAppendDefinitelyNullObjectTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public UnusedStringBuilderWithAppendDefinitelyNullObjectTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ MethodSubject mainMethod = inspector.clazz(Main.class).mainMethod();
+ assertThat(mainMethod, not(instantiatesClass(StringBuilder.class)));
+ assertThat(mainMethod, not(invokesMethodWithName("toString")));
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithEmptyOutput();
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ Object o = null;
+ new StringBuilder().append(o).toString();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderWithAppendMaybeNullObjectTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderWithAppendMaybeNullObjectTest.java
new file mode 100644
index 0000000..78c0a10
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderWithAppendMaybeNullObjectTest.java
@@ -0,0 +1,68 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.string;
+
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.instantiatesClass;
+import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class UnusedStringBuilderWithAppendMaybeNullObjectTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public UnusedStringBuilderWithAppendMaybeNullObjectTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ MethodSubject mainMethod = inspector.clazz(Main.class).mainMethod();
+ assertThat(
+ mainMethod,
+ notIf(
+ instantiatesClass(StringBuilder.class),
+ canUseJavaUtilObjects(parameters) || parameters.isDexRuntime()));
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithEmptyOutput();
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ A a = System.currentTimeMillis() < 0 ? new A() : null;
+ new StringBuilder().append(a).toString();
+ }
+ }
+
+ static class A {
+
+ @Override
+ public String toString() {
+ return "A";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderWithAppendObjectSideEffectTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderWithAppendObjectSideEffectTest.java
new file mode 100644
index 0000000..934dfd2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderWithAppendObjectSideEffectTest.java
@@ -0,0 +1,64 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.string;
+
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.instantiatesClass;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class UnusedStringBuilderWithAppendObjectSideEffectTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public UnusedStringBuilderWithAppendObjectSideEffectTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ MethodSubject mainMethod = inspector.clazz(Main.class).mainMethod();
+ assertThat(mainMethod, not(instantiatesClass(StringBuilder.class)));
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("A");
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ new StringBuilder().append(new A()).toString();
+ }
+ }
+
+ static class A {
+
+ @Override
+ public String toString() {
+ System.out.println("A");
+ return "A";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderWithAppendObjectTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderWithAppendObjectTest.java
new file mode 100644
index 0000000..d8ed11c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/UnusedStringBuilderWithAppendObjectTest.java
@@ -0,0 +1,68 @@
+// Copyright (c) 2020, the R8 project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+package com.android.tools.r8.ir.optimize.string;
+
+import static com.android.tools.r8.utils.codeinspector.CodeMatchers.instantiatesClass;
+import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class UnusedStringBuilderWithAppendObjectTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public UnusedStringBuilderWithAppendObjectTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ MethodSubject mainMethod = inspector.clazz(Main.class).mainMethod();
+ assertThat(
+ mainMethod,
+ notIf(
+ instantiatesClass(StringBuilder.class),
+ canUseJavaUtilObjects(parameters) || parameters.isDexRuntime()));
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithEmptyOutput();
+ }
+
+ static class Main {
+
+ public static void main(String[] args) {
+ A a = System.currentTimeMillis() > 0 ? new A() : null;
+ new StringBuilder().append(a).toString();
+ }
+ }
+
+ static class A {
+
+ @Override
+ public String toString() {
+ return "A";
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapInvalidOrdinalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapInvalidOrdinalTest.java
index cbbd4f0..a779afb 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapInvalidOrdinalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/switches/SwitchMapInvalidOrdinalTest.java
@@ -13,6 +13,7 @@
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
+@SuppressWarnings("unchecked")
@RunWith(Parameterized.class)
public class SwitchMapInvalidOrdinalTest extends TestBase {
private final TestParameters parameters;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizationsTemplates.java b/src/test/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizationsTemplates.java
index d8d7c85..8f7c579 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizationsTemplates.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/templates/CfUtilityMethodsForCodeOptimizationsTemplates.java
@@ -6,6 +6,12 @@
public class CfUtilityMethodsForCodeOptimizationsTemplates {
+ public static void toStringIfNotNull(Object o) {
+ if (o != null) {
+ o.toString();
+ }
+ }
+
public static void throwClassCastExceptionIfNotNull(Object o) {
if (o != null) {
throw new ClassCastException();
diff --git a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
index fa7b74e..dff06df 100644
--- a/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/regalloc/RegisterMoveSchedulerTest.java
@@ -73,6 +73,12 @@
}
@Override
+ public void replaceCurrentInstructionWithConstString(
+ AppView<?> appView, IRCode code, DexString value) {
+ throw new Unimplemented();
+ }
+
+ @Override
public void replaceCurrentInstructionWithStaticGet(
AppView<?> appView, IRCode code, DexField field, Set<Value> affectedValues) {
throw new Unimplemented();
@@ -151,6 +157,12 @@
}
@Override
+ public BasicBlock splitCopyCatchHandlers(
+ IRCode code, ListIterator<BasicBlock> blockIterator, InternalOptions options) {
+ throw new Unimplemented();
+ }
+
+ @Override
public BasicBlock inlineInvoke(
AppView<?> appView,
IRCode code,
diff --git a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
index f76758c..0abfe16 100644
--- a/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/AbstractR8KotlinTestBase.java
@@ -14,6 +14,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestRunResult;
@@ -51,13 +52,16 @@
private final List<Path> extraClasspath = new ArrayList<>();
// Some tests defined in subclasses, e.g., Metadata tests, don't care about access relaxation.
- protected AbstractR8KotlinTestBase(KotlinTargetVersion kotlinTargetVersion) {
- this(kotlinTargetVersion, false);
+ protected AbstractR8KotlinTestBase(
+ KotlinTargetVersion kotlinTargetVersion, KotlinCompiler kotlinc) {
+ this(kotlinTargetVersion, kotlinc, false);
}
protected AbstractR8KotlinTestBase(
- KotlinTargetVersion kotlinTargetVersion, boolean allowAccessModification) {
- super(kotlinTargetVersion);
+ KotlinTargetVersion kotlinTargetVersion,
+ KotlinCompiler kotlinc,
+ boolean allowAccessModification) {
+ super(kotlinTargetVersion, kotlinc);
this.allowAccessModification = allowAccessModification;
}
@@ -238,9 +242,14 @@
throws Exception {
Assume.assumeTrue(ToolHelper.artSupported() || ToolHelper.compareAgaintsGoldenFiles());
+ Path kotlinJarFile =
+ getCompileMemoizer(getKotlinFilesInResource(folder), folder)
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect())
+ .getForConfiguration(kotlinc, targetVersion);
+
// Build classpath for compilation (and java execution)
classpath.clear();
- classpath.add(getKotlinJarFile(folder));
+ classpath.add(kotlinJarFile);
classpath.add(getJavaJarFile(folder));
classpath.addAll(extraClasspath);
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
index 2bb0867..a949213 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
@@ -12,6 +13,7 @@
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.ThrowableConsumer;
@@ -43,14 +45,15 @@
@RunWith(Parameterized.class)
public class KotlinClassInlinerTest extends AbstractR8KotlinTestBase {
- @Parameterized.Parameters(name = "target: {0}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
public static Collection<Object[]> data() {
- return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values());
+ return buildParameters(
+ KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
}
public KotlinClassInlinerTest(
- KotlinTargetVersion targetVersion, boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
+ super(targetVersion, kotlinc, allowAccessModification);
}
private static boolean isLambda(DexClass clazz) {
@@ -332,7 +335,7 @@
// condition.
options.testing.addCallEdgesForLibraryInvokes = true;
- options.enableHorizontalClassMergingOfKotlinLambdas = false;
+ options.horizontalClassMergerOptions().disableKotlinLambdaMerging();
})
.apply(configuration));
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassStaticizerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassStaticizerTest.java
index bf74d90..ec1793d 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassStaticizerTest.java
@@ -4,12 +4,14 @@
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.BooleanUtils;
@@ -24,14 +26,15 @@
@RunWith(Parameterized.class)
public class KotlinClassStaticizerTest extends AbstractR8KotlinTestBase {
- @Parameterized.Parameters(name = "target: {0}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
public static Collection<Object[]> data() {
- return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values());
+ return buildParameters(
+ KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
}
public KotlinClassStaticizerTest(
- KotlinTargetVersion targetVersion, boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
+ super(targetVersion, kotlinc, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinDuplicateAnnotationTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinDuplicateAnnotationTest.java
index 35e3109..7407d46 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinDuplicateAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinDuplicateAnnotationTest.java
@@ -3,12 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.fail;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.BooleanUtils;
@@ -34,11 +36,12 @@
o.enableInlining = false;
};
- @Parameterized.Parameters(name = "{0} target: {1}, allowAccessModification: {2}")
+ @Parameterized.Parameters(name = "{0} target: {1}, kotlinc: {2}, allowAccessModification: {3}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimes().build(),
KotlinTargetVersion.values(),
+ getKotlinCompilers(),
BooleanUtils.values());
}
@@ -47,17 +50,22 @@
public KotlinDuplicateAnnotationTest(
TestParameters parameters,
KotlinTargetVersion targetVersion,
+ KotlinCompiler kotlinc,
boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ super(targetVersion, kotlinc, allowAccessModification);
this.parameters = parameters;
}
+ private static final KotlinCompileMemoizer compiledJars =
+ getCompileMemoizer(getKotlinFilesInResource(FOLDER), FOLDER)
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect());
+
@Test
public void test_dex() {
assumeTrue("test DEX", parameters.isDexRuntime());
try {
testForR8(parameters.getBackend())
- .addProgramFiles(getKotlinJarFile(FOLDER))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
.addKeepMainRule(MAIN)
.addKeepRules(KEEP_RULES)
.noMinification()
@@ -74,7 +82,7 @@
public void test_cf() throws Exception {
assumeTrue("test CF", parameters.isCfRuntime());
testForR8(parameters.getBackend())
- .addProgramFiles(getKotlinJarFile(FOLDER))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
.addKeepMainRule(MAIN)
.addKeepRules(KEEP_RULES)
.noMinification()
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
index dc917ab..c683b1a 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinIntrinsicsInlineTest.java
@@ -3,11 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.BooleanUtils;
@@ -24,11 +26,12 @@
private static final String FOLDER = "intrinsics";
private static final String MAIN = FOLDER + ".InlineKt";
- @Parameterized.Parameters(name = "{0} target: {1}, allowAccessModification: {2}")
+ @Parameterized.Parameters(name = "{0} target: {1}, kotlinc: {2}, allowAccessModification: {3}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimes().build(),
KotlinTargetVersion.values(),
+ getKotlinCompilers(),
BooleanUtils.values());
}
@@ -37,41 +40,46 @@
public KotlinIntrinsicsInlineTest(
TestParameters parameters,
KotlinTargetVersion targetVersion,
+ KotlinCompiler kotlinc,
boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ super(targetVersion, kotlinc, allowAccessModification);
this.parameters = parameters;
}
+ private static final KotlinCompileMemoizer compiledJars =
+ getCompileMemoizer(getKotlinFilesInResource(FOLDER), FOLDER)
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect());
+
@Test
public void b139432507() throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(getKotlinJarFile(FOLDER))
- .addKeepRules(StringUtils.lines(
- "-keepclasseswithmembers class " + MAIN + "{",
- " public static *** *(...);",
- "}"))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+ .addKeepRules(
+ StringUtils.lines(
+ "-keepclasseswithmembers class " + MAIN + "{", " public static *** *(...);", "}"))
.allowAccessModification(allowAccessModification)
.noMinification()
.setMinApi(parameters.getRuntime())
.compile()
- .inspect(inspector -> {
- ClassSubject main = inspector.clazz(MAIN);
- assertThat(main, isPresent());
+ .inspect(
+ inspector -> {
+ ClassSubject main = inspector.clazz(MAIN);
+ assertThat(main, isPresent());
- // Note that isSupported itself has a parameter whose null check would be inlined
- // with -allowaccessmodification.
- MethodSubject isSupported = main.uniqueMethodWithName("isSupported");
- assertThat(isSupported, isPresent());
- assertEquals(
- allowAccessModification ? 0 : 1,
- countCall(isSupported, "checkParameterIsNotNull"));
+ // Note that isSupported itself has a parameter whose null check would be inlined
+ // with -allowaccessmodification.
+ MethodSubject isSupported = main.uniqueMethodWithName("isSupported");
+ assertThat(isSupported, isPresent());
+ assertEquals(
+ allowAccessModification ? 0 : 1,
+ countCall(isSupported, "checkParameterIsNotNull"));
- // In general cases, null check won't be invoked only once or twice, hence no subtle
- // situation in double inlining.
- MethodSubject containsArray = main.uniqueMethodWithName("containsArray");
- assertThat(containsArray, isPresent());
- assertEquals(0, countCall(containsArray, "checkParameterIsNotNull"));
- });
+ // In general cases, null check won't be invoked only once or twice, hence no subtle
+ // situation in double inlining.
+ MethodSubject containsArray = main.uniqueMethodWithName("containsArray");
+ assertThat(containsArray, isPresent());
+ assertEquals(0, countCall(containsArray, "checkParameterIsNotNull"));
+ });
}
@Test
@@ -88,27 +96,29 @@
private void testSingle(String methodName) throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(getKotlinJarFile(FOLDER))
- .addKeepRules(StringUtils.lines(
- "-keepclasseswithmembers class " + MAIN + "{",
- " public static *** " + methodName + "(...);",
- "}"))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+ .addKeepRules(
+ StringUtils.lines(
+ "-keepclasseswithmembers class " + MAIN + "{",
+ " public static *** " + methodName + "(...);",
+ "}"))
.allowAccessModification(allowAccessModification)
.noMinification()
.setMinApi(parameters.getRuntime())
.compile()
- .inspect(inspector -> {
- ClassSubject main = inspector.clazz(MAIN);
- assertThat(main, isPresent());
+ .inspect(
+ inspector -> {
+ ClassSubject main = inspector.clazz(MAIN);
+ assertThat(main, isPresent());
- MethodSubject method = main.uniqueMethodWithName(methodName);
- assertThat(method, isPresent());
- int arity = method.getMethod().method.getArity();
- // One from the method's own argument, if any, and
- // Two from Array utils, `contains` and `indexOf`, if inlined with access relaxation.
- assertEquals(
- allowAccessModification ? 0 : arity + 2,
- countCall(method, "checkParameterIsNotNull"));
- });
+ MethodSubject method = main.uniqueMethodWithName(methodName);
+ assertThat(method, isPresent());
+ int arity = method.getMethod().method.getArity();
+ // One from the method's own argument, if any, and
+ // Two from Array utils, `contains` and `indexOf`, if inlined with access relaxation.
+ assertEquals(
+ allowAccessModification ? 0 : arity + 2,
+ countCall(method, "checkParameterIsNotNull"));
+ });
}
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java
index 3c28a7d..b59d98c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedArgumentsInLambdasTest.java
@@ -3,11 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -20,14 +22,15 @@
@RunWith(Parameterized.class)
public class KotlinUnusedArgumentsInLambdasTest extends AbstractR8KotlinTestBase {
- @Parameterized.Parameters(name = "target: {0}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
public static Collection<Object[]> data() {
- return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values());
+ return buildParameters(
+ KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
}
public KotlinUnusedArgumentsInLambdasTest(
- KotlinTargetVersion targetVersion, boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
+ super(targetVersion, kotlinc, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java
index 10fe60e..c358325 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinUnusedSingletonTest.java
@@ -3,12 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -25,17 +27,18 @@
@RunWith(Parameterized.class)
public class KotlinUnusedSingletonTest extends AbstractR8KotlinTestBase {
- @Parameterized.Parameters(name = "target: {0}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
- return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values());
+ return buildParameters(
+ KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
}
private static final String printlnSignature =
"void java.io.PrintStream.println(java.lang.Object)";
public KotlinUnusedSingletonTest(
- KotlinTargetVersion targetVersion, boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
+ super(targetVersion, kotlinc, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
index e29373a..e90a8b6 100644
--- a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinReflectionLibTest.java
@@ -3,6 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestParameters;
@@ -18,18 +21,21 @@
@RunWith(Parameterized.class)
public class ProcessKotlinReflectionLibTest extends KotlinTestBase {
- private final TestParameters parameters;
- public ProcessKotlinReflectionLibTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
- this.parameters = parameters;
- }
+ private final TestParameters parameters;
@Parameterized.Parameters(name = "{0} target: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withAllRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withAllRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
+ }
+
+ public ProcessKotlinReflectionLibTest(
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
+ this.parameters = parameters;
}
private void test(Collection<String> rules) throws Exception {
@@ -39,8 +45,9 @@
private void test(
Collection<String> rules, ThrowableConsumer<R8FullTestBuilder> consumer) throws Exception {
testForR8(parameters.getBackend())
- .addLibraryFiles(ToolHelper.getMostRecentAndroidJar(), ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(ToolHelper.getKotlinReflectJar())
+ .addLibraryFiles(
+ ToolHelper.getMostRecentAndroidJar(), ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinc))
.addKeepRules(rules)
.addKeepAttributes(ProguardKeepAttributes.SIGNATURE)
.addKeepAttributes(ProguardKeepAttributes.INNER_CLASSES)
diff --git a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
index 195b536..7b3fd69 100644
--- a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
@@ -3,6 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestParameters;
@@ -20,15 +23,18 @@
public class ProcessKotlinStdlibTest extends KotlinTestBase {
private final TestParameters parameters;
- public ProcessKotlinStdlibTest(TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
- this.parameters = parameters;
- }
-
@Parameterized.Parameters(name = "{0} target: {1}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withAllRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withAllRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
+ }
+
+ public ProcessKotlinStdlibTest(
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
+ this.parameters = parameters;
}
private void test(Collection<String> rules, boolean expectInvalidFoo) throws Exception {
@@ -41,7 +47,7 @@
ThrowableConsumer<R8FullTestBuilder> consumer)
throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addKeepRules(rules)
.addKeepAttributes(ProguardKeepAttributes.SIGNATURE)
.addKeepAttributes(ProguardKeepAttributes.INNER_CLASSES)
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
index b4aeced..cd5d8b1 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinAccessorTest.java
@@ -4,10 +4,12 @@
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -65,14 +67,15 @@
.addProperty("property", JAVA_LANG_STRING, Visibility.PRIVATE)
.addProperty("indirectPropertyGetter", JAVA_LANG_STRING, Visibility.PRIVATE);
- @Parameterized.Parameters(name = "target: {0}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
public static Collection<Object[]> data() {
- return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values());
+ return buildParameters(
+ KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
}
public R8KotlinAccessorTest(
- KotlinTargetVersion targetVersion, boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
+ super(targetVersion, kotlinc, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
index ec0ee03..ef13161 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinDataClassTest.java
@@ -4,6 +4,9 @@
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.kotlin.TestKotlinClass.Visibility;
@@ -42,14 +45,15 @@
private Consumer<InternalOptions> disableClassInliner = o -> o.enableClassInlining = false;
- @Parameterized.Parameters(name = "target: {0}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "target: {0}, kotlinc: {2}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
- return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values());
+ return buildParameters(
+ KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
}
public R8KotlinDataClassTest(
- KotlinTargetVersion targetVersion, boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
+ super(targetVersion, kotlinc, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
index 770d6cc..ea12c12 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinIntrinsicsTest.java
@@ -4,6 +4,9 @@
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.BooleanUtils;
@@ -23,14 +26,15 @@
private static final TestKotlinDataClass KOTLIN_INTRINSICS_CLASS =
new TestKotlinDataClass("kotlin.jvm.internal.Intrinsics");
- @Parameterized.Parameters(name = "target: {0}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
public static Collection<Object[]> data() {
- return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values());
+ return buildParameters(
+ KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
}
public R8KotlinIntrinsicsTest(
- KotlinTargetVersion targetVersion, boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
+ super(targetVersion, kotlinc, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
index 30511bb..e04585c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/R8KotlinPropertiesTest.java
@@ -4,8 +4,10 @@
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.TestKotlinClass.Visibility;
import com.android.tools.r8.naming.MemberNaming;
@@ -93,14 +95,15 @@
o.enableClassStaticizer = false;
};
- @Parameterized.Parameters(name = "target: {0}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {1}")
public static Collection<Object[]> data() {
- return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values());
+ return buildParameters(
+ KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
}
public R8KotlinPropertiesTest(
- KotlinTargetVersion targetVersion, boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
+ super(targetVersion, kotlinc, allowAccessModification);
}
@Test
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 d56d0f0..70fd115 100644
--- a/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/SimplifyIfNotNullKotlinTest.java
@@ -3,8 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
import com.android.tools.r8.utils.BooleanUtils;
@@ -21,14 +23,15 @@
private static final String FOLDER = "non_null";
private static final String STRING = "java.lang.String";
- @Parameterized.Parameters(name = "target: {0}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
public static Collection<Object[]> data() {
- return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values());
+ return buildParameters(
+ KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
}
public SimplifyIfNotNullKotlinTest(
- KotlinTargetVersion targetVersion, boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
+ super(targetVersion, kotlinc, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/coroutines/KotlinxCoroutinesTestRunner.java b/src/test/java/com/android/tools/r8/kotlin/coroutines/KotlinxCoroutinesTestRunner.java
index 6df1462..9ae5aed 100644
--- a/src/test/java/com/android/tools/r8/kotlin/coroutines/KotlinxCoroutinesTestRunner.java
+++ b/src/test/java/com/android/tools/r8/kotlin/coroutines/KotlinxCoroutinesTestRunner.java
@@ -4,9 +4,10 @@
package com.android.tools.r8.kotlin.coroutines;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -49,16 +50,19 @@
private Set<String> notWorkingTests =
Sets.newHashSet("kotlinx.coroutines.test.TestDispatchersTest");
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
private final TestParameters parameters;
- public KotlinxCoroutinesTestRunner(TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ public KotlinxCoroutinesTestRunner(
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
@@ -88,7 +92,7 @@
}
private Path compileTestSources(Path baseJar) throws Exception {
- return kotlinc(KOTLINC, targetVersion)
+ return kotlinc(kotlinc, targetVersion)
.addArguments(
"-Xuse-experimental=kotlinx.coroutines.InternalCoroutinesApi",
"-Xuse-experimental=kotlinx.coroutines.ObsoleteCoroutinesApi",
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/JStyleKotlinLambdaMergingWithEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/JStyleKotlinLambdaMergingWithEnumUnboxingTest.java
index 1aef013..7103667 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/JStyleKotlinLambdaMergingWithEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/JStyleKotlinLambdaMergingWithEnumUnboxingTest.java
@@ -4,17 +4,20 @@
package com.android.tools.r8.kotlin.lambda;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoHorizontalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.ir.optimize.lambda.kotlin.JStyleLambdaGroupIdFactory;
import com.android.tools.r8.ir.optimize.lambda.kotlin.KotlinLambdaGroupIdFactory;
import com.android.tools.r8.kotlin.lambda.JStyleKotlinLambdaMergingWithEnumUnboxingTest.Main.EnumUnboxingCandidate;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -24,14 +27,19 @@
public class JStyleKotlinLambdaMergingWithEnumUnboxingTest extends TestBase {
private final TestParameters parameters;
+ private final KotlinCompiler kotlinc;
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return TestBase.getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ @Parameters(name = "{0}, kotlinc: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ TestBase.getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getKotlinCompilers());
}
- public JStyleKotlinLambdaMergingWithEnumUnboxingTest(TestParameters parameters) {
+ public JStyleKotlinLambdaMergingWithEnumUnboxingTest(
+ TestParameters parameters, KotlinCompiler kotlinc) {
this.parameters = parameters;
+ this.kotlinc = kotlinc;
}
@Test
@@ -39,7 +47,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
.addDefaultRuntimeLibrary(parameters)
- .addLibraryFiles(ToolHelper.getKotlinStdlibJar())
+ .addLibraryFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addKeepMainRule(Main.class)
.addOptionsModification(
options ->
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java
index 6edeebc..b9baae8 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KStyleKotlinLambdaMergingWithEnumUnboxingTest.java
@@ -4,17 +4,20 @@
package com.android.tools.r8.kotlin.lambda;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.NoHorizontalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.ir.optimize.lambda.kotlin.KStyleLambdaGroupIdFactory;
import com.android.tools.r8.ir.optimize.lambda.kotlin.KotlinLambdaGroupIdFactory;
import com.android.tools.r8.kotlin.lambda.KStyleKotlinLambdaMergingWithEnumUnboxingTest.Main.EnumUnboxingCandidate;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -24,21 +27,26 @@
public class KStyleKotlinLambdaMergingWithEnumUnboxingTest extends TestBase {
private final TestParameters parameters;
+ private final KotlinCompiler kotlinc;
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return TestBase.getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ @Parameters(name = "{0}, kotlinc: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ TestBase.getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getKotlinCompilers());
}
- public KStyleKotlinLambdaMergingWithEnumUnboxingTest(TestParameters parameters) {
+ public KStyleKotlinLambdaMergingWithEnumUnboxingTest(
+ TestParameters parameters, KotlinCompiler kotlinc) {
this.parameters = parameters;
+ this.kotlinc = kotlinc;
}
@Test
public void test() throws Exception {
testForR8(parameters.getBackend())
.addInnerClasses(getClass())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addKeepMainRule(Main.class)
.addOptionsModification(
options ->
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java
index f28f68b..1b6d4c0 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergerValidationTest.java
@@ -3,10 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.lambda;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.TestRuntime.CfRuntime;
@@ -25,15 +26,17 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withAllRuntimesAndApiLevels().build(), KotlinTargetVersion.values());
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public KotlinLambdaMergerValidationTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion, false);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc, false);
this.parameters = parameters;
}
@@ -46,17 +49,17 @@
CfRuntime cfRuntime =
parameters.isCfRuntime() ? parameters.getRuntime().asCf() : TestRuntime.getCheckedInJdk9();
Path ktClasses =
- kotlinc(cfRuntime, KOTLINC, targetVersion)
+ kotlinc(cfRuntime, kotlinc, targetVersion)
.addSourceFiles(getKotlinFileInTest(folder, "b143165163"))
.compile();
testForR8(parameters.getBackend())
.addLibraryFiles(ToolHelper.getJava8RuntimeJar())
- .addLibraryFiles(ToolHelper.getKotlinStdlibJar())
+ .addLibraryFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addProgramFiles(ktClasses)
.addKeepMainRule("**.B143165163Kt")
.setMinApi(parameters.getApiLevel())
.compile()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar())
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.run(parameters.getRuntime(), pkg + ".B143165163Kt")
.assertSuccessWithOutputLines("outer foo bar", "outer foo default");
}
@@ -70,11 +73,11 @@
CfRuntime cfRuntime =
parameters.isCfRuntime() ? parameters.getRuntime().asCf() : TestRuntime.getCheckedInJdk9();
Path ktClasses =
- kotlinc(cfRuntime, KOTLINC, targetVersion)
+ kotlinc(cfRuntime, kotlinc, targetVersion)
.addSourceFiles(getKotlinFileInTest(folder, "b143165163"))
.compile();
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addProgramFiles(ktClasses)
.addKeepMainRule("**.B143165163Kt")
.allowDiagnosticWarningMessages()
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingDebugTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingDebugTest.java
index 3a795be..e7c4762 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingDebugTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingDebugTest.java
@@ -3,13 +3,15 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.lambda;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.hamcrest.CoreMatchers.equalTo;
import com.android.tools.r8.CompilationMode;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -23,20 +25,25 @@
private static final String MAIN_CLASS = "reprocess_merged_lambdas_kstyle.MainKt";
@Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(), getKotlinCompilers());
}
- public KotlinLambdaMergingDebugTest(TestParameters parameters) {
- super(KotlinTargetVersion.JAVA_6);
+ public KotlinLambdaMergingDebugTest(TestParameters parameters, KotlinCompiler kotlinc) {
+ super(KotlinTargetVersion.JAVA_6, kotlinc);
this.parameters = parameters;
}
+ private static final KotlinCompileMemoizer compiledJars =
+ getCompileMemoizer(getKotlinFilesInResource(FOLDER), FOLDER)
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect());
+
@Test
public void testMergingKStyleLambdasAndReprocessingInDebug() throws Exception {
testForR8(parameters.getBackend())
.setMode(CompilationMode.DEBUG)
- .addProgramFiles(getKotlinJarFile(FOLDER))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, KotlinTargetVersion.JAVA_6))
.addProgramFiles(getJavaJarFile(FOLDER))
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(MAIN_CLASS)
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTest.java
index 4f3ea88..b9e0546 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingTest.java
@@ -4,12 +4,14 @@
package com.android.tools.r8.kotlin.lambda;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.google.common.base.Predicates.alwaysTrue;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.fail;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexType;
@@ -40,23 +42,29 @@
// Ensure that enclosing method and inner class attributes are kept even on classes that are
// not explicitly mentioned by a keep rule.
options.forceProguardCompatibility = true;
- options.enableHorizontalClassMergingOfKotlinLambdas = false;
+ options.horizontalClassMergerOptions().disableKotlinLambdaMerging();
}
private final boolean enableUnusedInterfaceRemoval;
@Parameterized.Parameters(
- name = "target: {0}, allow access modification: {1}, unused interface removal: {2}")
+ name =
+ "target: {0}, kotlinc: {1}, allow access modification: {2}, unused interface removal:"
+ + " {3}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(), BooleanUtils.values(), BooleanUtils.values());
+ KotlinTargetVersion.values(),
+ getKotlinCompilers(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
}
public KotlinLambdaMergingTest(
KotlinTargetVersion targetVersion,
+ KotlinCompiler kotlinc,
boolean allowAccessModification,
boolean enableUnusedInterfaceRemoval) {
- super(targetVersion, allowAccessModification);
+ super(targetVersion, kotlinc, allowAccessModification);
this.enableUnusedInterfaceRemoval = enableUnusedInterfaceRemoval;
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithReprocessingTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithReprocessingTest.java
index d6e8c53..b1b38b9 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithReprocessingTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithReprocessingTest.java
@@ -3,6 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.lambda;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
import com.android.tools.r8.utils.BooleanUtils;
@@ -14,14 +17,15 @@
@RunWith(Parameterized.class)
public class KotlinLambdaMergingWithReprocessingTest extends AbstractR8KotlinTestBase {
- @Parameterized.Parameters(name = "target: {0}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
public static Collection<Object[]> data() {
- return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values());
+ return buildParameters(
+ KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
}
public KotlinLambdaMergingWithReprocessingTest(
- KotlinTargetVersion targetVersion, boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
+ super(targetVersion, kotlinc, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithSmallInliningBudgetTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithSmallInliningBudgetTest.java
index 127c1e3..1dcdcfb 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithSmallInliningBudgetTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/KotlinLambdaMergingWithSmallInliningBudgetTest.java
@@ -3,6 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.lambda;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
import com.android.tools.r8.utils.BooleanUtils;
@@ -14,14 +17,15 @@
@RunWith(Parameterized.class)
public class KotlinLambdaMergingWithSmallInliningBudgetTest extends AbstractR8KotlinTestBase {
- @Parameterized.Parameters(name = "target: {0}, allowAccessModification: {1}")
+ @Parameterized.Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}")
public static Collection<Object[]> data() {
- return buildParameters(KotlinTargetVersion.values(), BooleanUtils.values());
+ return buildParameters(
+ KotlinTargetVersion.values(), getKotlinCompilers(), BooleanUtils.values());
}
public KotlinLambdaMergingWithSmallInliningBudgetTest(
- KotlinTargetVersion targetVersion, boolean allowAccessModification) {
- super(targetVersion, allowAccessModification);
+ KotlinTargetVersion targetVersion, KotlinCompiler kotlinc, boolean allowAccessModification) {
+ super(targetVersion, kotlinc, allowAccessModification);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java
index d764d5f..0dd8a62 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b148525512/B148525512.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.kotlin.lambda.b148525512;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
@@ -12,6 +12,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestParameters;
@@ -22,16 +23,13 @@
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.io.IOException;
+import java.nio.file.Files;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.stream.Collectors;
-import org.junit.BeforeClass;
-import org.junit.ClassRule;
import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -44,43 +42,45 @@
private static final String featureKtClassNamet = kotlinTestClassesPackage + ".FeatureKt";
private static final String baseClassName = kotlinTestClassesPackage + ".Base";
- private static final Map<KotlinTargetVersion, Path> kotlinBaseClasses = new HashMap<>();
- private static final Map<KotlinTargetVersion, Path> kotlinFeatureClasses = new HashMap<>();
+ private static final KotlinCompileMemoizer kotlinBaseClasses =
+ getCompileMemoizer(getKotlinFileInTestPackage(pkg, "base"))
+ .configure(
+ kotlinCompilerTool -> kotlinCompilerTool.addClasspathFiles(getFeatureApiPath()));
+ private static final KotlinCompileMemoizer kotlinFeatureClasses =
+ getCompileMemoizer(getKotlinFileInTestPackage(pkg, "feature"))
+ .configure(
+ kotlinCompilerTool -> {
+ // Compile the feature Kotlin code with the base classes on classpath.
+ kotlinCompilerTool.addClasspathFiles(
+ kotlinBaseClasses.getForConfiguration(
+ kotlinCompilerTool.getCompiler(), kotlinCompilerTool.getTargetVersion()));
+ });
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0},{1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withDexRuntimes().withAllApiLevels().build(),
- KotlinTargetVersion.values());
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
- public B148525512(TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ public B148525512(
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- @ClassRule public static TemporaryFolder classTemp = new TemporaryFolder();
-
- @BeforeClass
- public static void compileKotlin() throws Exception {
- // Compile the base Kotlin with the FeatureAPI Java class on classpath.
- Path featureApiJar = classTemp.newFile("feature_api.jar").toPath();
- writeClassesToJar(featureApiJar, FeatureAPI.class);
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path ktBaseClasses =
- kotlinc(KOTLINC, targetVersion)
- .addClasspathFiles(featureApiJar)
- .addSourceFiles(getKotlinFileInTestPackage(pkg, "base"))
- .compile();
- kotlinBaseClasses.put(targetVersion, ktBaseClasses);
- // Compile the feature Kotlin code with the base classes on classpath.
- Path ktFeatureClasses =
- kotlinc(KOTLINC, targetVersion)
- .addClasspathFiles(ktBaseClasses)
- .addSourceFiles(getKotlinFileInTestPackage(pkg, "feature"))
- .compile();
- kotlinFeatureClasses.put(targetVersion, ktFeatureClasses);
+ private static Path getFeatureApiPath() {
+ try {
+ Path featureApiJar = getStaticTemp().getRoot().toPath().resolve("feature_api.jar");
+ if (Files.exists(featureApiJar)) {
+ return featureApiJar;
+ }
+ writeClassesToJar(featureApiJar, FeatureAPI.class);
+ return featureApiJar;
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
}
@@ -118,15 +118,15 @@
Path featureCode = temp.newFile("feature.zip").toPath();
R8TestCompileResult compileResult =
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(kotlinBaseClasses.get(targetVersion))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(kotlinBaseClasses.getForConfiguration(kotlinc, targetVersion))
.addProgramClasses(FeatureAPI.class)
.addKeepMainRule(baseKtClassName)
.addKeepClassAndMembersRules(baseClassName)
.addKeepClassAndMembersRules(featureKtClassNamet)
.addKeepClassAndMembersRules(FeatureAPI.class)
.addOptionsModification(
- options -> options.enableHorizontalClassMergingOfKotlinLambdas = false)
+ options -> options.horizontalClassMergerOptions().disableKotlinLambdaMerging())
.setMinApi(parameters.getApiLevel())
.noMinification() // The check cast inspection above relies on original names.
.addFeatureSplit(
@@ -134,7 +134,8 @@
builder
.addProgramResourceProvider(
ArchiveResourceProvider.fromArchive(
- kotlinFeatureClasses.get(targetVersion), true))
+ kotlinFeatureClasses.getForConfiguration(kotlinc, targetVersion),
+ true))
.setProgramConsumer(new ArchiveConsumer(featureCode, false))
.build())
.allowDiagnosticWarningMessages()
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
index 73b42ed..57cdae7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
@@ -8,15 +8,17 @@
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.InternalOptions.HorizontalClassMergerOptions;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import java.io.IOException;
import java.nio.file.Path;
@@ -32,16 +34,20 @@
@RunWith(Parameterized.class)
public class LambdaGroupGCLimitTest extends TestBase {
+ private final boolean enableHorizontalClassMergingOfKotlinLambdas;
private final TestParameters parameters;
private final int LAMBDA_HOLDER_LIMIT = 50;
private final int LAMBDAS_PER_CLASS_LIMIT = 100;
- @Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ @Parameters(name = "{1}, horizontal class merging: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ BooleanUtils.values(), getTestParameters().withDexRuntimes().withAllApiLevels().build());
}
- public LambdaGroupGCLimitTest(TestParameters parameters) {
+ public LambdaGroupGCLimitTest(
+ boolean enableHorizontalClassMergingOfKotlinLambdas, TestParameters parameters) {
+ this.enableHorizontalClassMergingOfKotlinLambdas = enableHorizontalClassMergingOfKotlinLambdas;
this.parameters = parameters;
}
@@ -50,7 +56,12 @@
String PKG_NAME = LambdaGroupGCLimitTest.class.getPackage().getName();
R8FullTestBuilder testBuilder =
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(ToolHelper.getKotlinC_1_3_72()))
+ .addOptionsModification(
+ options ->
+ options
+ .horizontalClassMergerOptions()
+ .enableKotlinLambdaMergingIf(enableHorizontalClassMergingOfKotlinLambdas))
.setMinApi(parameters.getApiLevel())
.noMinification();
Path classFiles = temp.newFile("classes.jar").toPath();
@@ -63,7 +74,27 @@
testBuilder.addKeepClassAndMembersRules(PKG_NAME + ".MainKt" + mainId);
}
writeClassFileDataToJar(classFiles, classFileData);
- R8TestCompileResult compileResult = testBuilder.addProgramFiles(classFiles).compile();
+ R8TestCompileResult compileResult =
+ testBuilder
+ .addProgramFiles(classFiles)
+ .addHorizontallyMergedClassesInspector(
+ inspector -> {
+ if (enableHorizontalClassMergingOfKotlinLambdas) {
+ HorizontalClassMergerOptions defaultHorizontalClassMergerOptions =
+ new HorizontalClassMergerOptions();
+ assertEquals(4833, inspector.getSources().size());
+ assertEquals(167, inspector.getTargets().size());
+ assertTrue(
+ inspector.getMergeGroups().stream()
+ .allMatch(
+ mergeGroup ->
+ mergeGroup.size()
+ <= defaultHorizontalClassMergerOptions.getMaxGroupSize()));
+ } else {
+ inspector.assertNoClassesMerged();
+ }
+ })
+ .compile();
Path path = compileResult.writeToZip();
compileResult
.run(parameters.getRuntime(), PKG_NAME + ".MainKt0")
@@ -74,7 +105,9 @@
codeInspector.allClasses().stream()
.filter(c -> c.getFinalName().contains("LambdaGroup"))
.collect(Collectors.toList());
- assertEquals(1, lambdaGroups.size());
+ assertEquals(
+ 1 - BooleanUtils.intValue(enableHorizontalClassMergingOfKotlinLambdas),
+ lambdaGroups.size());
});
Path oatFile = temp.newFile("out.oat").toPath();
ProcessResult processResult =
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java
index 3926dea..c261c25 100644
--- a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaSplitByCodeCorrectnessTest.java
@@ -4,10 +4,11 @@
package com.android.tools.r8.kotlin.lambda.b159688129;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime;
import com.android.tools.r8.TestRuntime.CfRuntime;
@@ -33,17 +34,21 @@
private final KotlinTargetVersion targetVersion;
private final boolean splitGroup;
- @Parameters(name = "{0}, targetVersion: {1}, splitGroup: {2}")
+ @Parameters(name = "{0}, kotlinc: {2} targetVersion: {1}, splitGroup: {3}")
public static List<Object[]> data() {
return buildParameters(
getTestParameters().withDexRuntimes().withAllApiLevels().build(),
KotlinTargetVersion.values(),
+ getKotlinCompilers(),
BooleanUtils.values());
}
public LambdaSplitByCodeCorrectnessTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, boolean splitGroup) {
- super(targetVersion);
+ TestParameters parameters,
+ KotlinTargetVersion targetVersion,
+ KotlinCompiler kotlinc,
+ boolean splitGroup) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
this.targetVersion = targetVersion;
this.splitGroup = splitGroup;
@@ -56,12 +61,14 @@
CfRuntime cfRuntime =
parameters.isCfRuntime() ? parameters.getRuntime().asCf() : TestRuntime.getCheckedInJdk9();
Path ktClasses =
- kotlinc(cfRuntime, KOTLINC, targetVersion)
+ kotlinc(cfRuntime, kotlinc, targetVersion)
.addSourceFiles(getKotlinFileInTest(folder, "Simple"))
.compile();
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addProgramFiles(ktClasses)
+ .addOptionsModification(
+ options -> options.horizontalClassMergerOptions().disableKotlinLambdaMerging())
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(PKG_NAME + ".SimpleKt")
.applyIf(
@@ -70,8 +77,7 @@
b.addOptionsModification(
internalOptions ->
// Setting verificationSizeLimitInBytesOverride = 1 will force a a chain
- // having
- // only a single implementation method in each.
+ // having only a single implementation method in each.
internalOptions.testing.verificationSizeLimitInBytesOverride =
splitGroup ? 1 : -1))
.noMinification()
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java b/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java
index 99aaf1b..e158fc7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/KotlinMetadataTestBase.java
@@ -8,6 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNull;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
import com.android.tools.r8.kotlin.KotlinMetadataWriter;
@@ -21,8 +22,8 @@
public abstract class KotlinMetadataTestBase extends AbstractR8KotlinTestBase {
- public KotlinMetadataTestBase(KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ public KotlinMetadataTestBase(KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
}
static final String PKG = KotlinMetadataTestBase.class.getPackage().getName();
@@ -40,8 +41,8 @@
static final String KT_FUNCTION1 = "Lkotlin/Function1;";
static final String KT_COMPARABLE = "Lkotlin/Comparable;";
- public void assertEqualMetadata(CodeInspector originalInspector, CodeInspector rewrittenInspector)
- throws Exception {
+ public void assertEqualMetadata(
+ CodeInspector originalInspector, CodeInspector rewrittenInspector) {
for (FoundClassSubject clazzSubject : originalInspector.allClasses()) {
ClassSubject r8Clazz = rewrittenInspector.clazz(clazzSubject.getOriginalName());
assertThat(r8Clazz, isPresent());
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
index 76c2894..31b489a 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrimitiveTypeRewriteTest.java
@@ -4,13 +4,14 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.JvmTestRunResult;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -19,9 +20,6 @@
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -34,44 +32,36 @@
private static final String PKG_LIB = PKG + ".primitive_type_rewrite_lib";
private static final String PKG_APP = PKG + ".primitive_type_rewrite_app";
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, compiler: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataPrimitiveTypeRewriteTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
- .compile();
- libJars.put(targetVersion, baseLibJar);
- }
- }
+ private static final KotlinCompileMemoizer libJars =
+ getCompileMemoizer(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
@Test
public void smokeTest() throws Exception {
- Path libJar = libJars.get(targetVersion);
+ Path libJar = libJars.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutputLines(EXPECTED);
@@ -90,7 +80,9 @@
private void runTest(boolean keepUnit) throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar(), libJars.get(targetVersion))
+ .addProgramFiles(
+ ToolHelper.getKotlinStdlibJar(kotlinc),
+ libJars.getForConfiguration(kotlinc, targetVersion))
.addKeepAllClassesRuleWithAllowObfuscation()
.addKeepRules("-keep class " + PKG_LIB + ".LibKt { *; }")
.addKeepRules("-keep class kotlin.Metadata { *; }")
@@ -107,7 +99,7 @@
equalTo("Resource 'META-INF/MANIFEST.MF' already exists."))
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
@@ -115,7 +107,7 @@
.compile();
final JvmTestRunResult runResult =
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt");
if (keepUnit) {
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
index 77134d8..a048351 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataPrunedFieldsTest.java
@@ -4,23 +4,20 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.metadata.metadata_pruned_fields.Main;
import com.android.tools.r8.shaking.ProguardKeepAttributes;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -31,36 +28,28 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withAllRuntimesAndApiLevels().build(), KotlinTargetVersion.values());
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
- public MetadataPrunedFieldsTest(TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ public MetadataPrunedFieldsTest(
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String baseLibFolder = PKG_PREFIX + "/metadata_pruned_fields";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(baseLibFolder, "Methods"))
- .compile();
- libJars.put(targetVersion, baseLibJar);
- }
- }
+ private static final KotlinCompileMemoizer libJars =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/metadata_pruned_fields", "Methods"));
@Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(libJars.get(targetVersion))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
.addProgramClassFileData(Main.dump())
.addKeepRules("-keep class " + PKG + ".metadata_pruned_fields.MethodsKt { *; }")
.addKeepRules("-keep class kotlin.Metadata { *** pn(); }")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
index 549f834..ea9ed33 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAllowAccessModificationTest.java
@@ -4,12 +4,13 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertEquals;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.StringContains.containsString;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -21,9 +22,6 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -54,53 +52,40 @@
"staticPrivate",
"staticInternal");
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteAllowAccessModificationTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
- private static Map<KotlinTargetVersion, Path> libReferenceJars = new HashMap<>();
+ private static final KotlinCompileMemoizer libJars =
+ getCompileMemoizer(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
+ private static final KotlinCompileMemoizer libReferenceJars =
+ getCompileMemoizer(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib_reference"));
private final TestParameters parameters;
- @BeforeClass
- public static void createLibJar() throws Exception {
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- libJars.put(
- targetVersion,
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
- .compile());
- libReferenceJars.put(
- targetVersion,
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- getKotlinFileInTest(
- DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib_reference"))
- .compile());
- }
- }
-
@Test
public void smokeTest() throws Exception {
- Path libJar = libReferenceJars.get(targetVersion);
+ Path libJar = libReferenceJars.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -113,7 +98,7 @@
// running with R8, the output should be binary compatible with libReference.
Path libJar =
testForR8(parameters.getBackend())
- .addProgramFiles(libJars.get(targetVersion))
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
.addKeepRules("-keepclassmembers,allowaccessmodification class **.Lib { *; }")
.addKeepRules("-keep,allowaccessmodification,allowobfuscation class **.Lib { *; }")
.addKeepRules("-keepclassmembers,allowaccessmodification class **.Lib$Comp { *; }")
@@ -134,7 +119,7 @@
.inspect(this::inspect)
.writeToZip();
ProcessResult mainResult =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
@@ -144,7 +129,7 @@
assertThat(mainResult.stderr, containsString("cannot access 'LibReference'"));
}
- private void inspect(CodeInspector inspector) throws Exception {
+ private void inspect(CodeInspector inspector) {
// TODO(b/154348683): Assert equality between LibReference and Lib.
// assertEqualMetadata(new CodeInspector(libReferenceJars.get(targetVersion)), inspector);
ClassSubject lib = inspector.clazz(PKG_LIB + ".Lib");
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
index 0b65d77..428103f 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnnotationTest.java
@@ -4,13 +4,14 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -22,12 +23,10 @@
import com.android.tools.r8.utils.codeinspector.KmTypeAliasSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.Map;
import kotlinx.metadata.KmAnnotation;
import kotlinx.metadata.KmAnnotationArgument;
import kotlinx.metadata.KmAnnotationArgument.ArrayValue;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -59,38 +58,30 @@
private static final String FOO_ORIGINAL_NAME = PKG_LIB + ".Foo";
private static final String FOO_FINAL_NAME = "a.b.c";
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteAnnotationTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+ private static final KotlinCompileMemoizer libJars =
+ getCompileMemoizer(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
private final TestParameters parameters;
- @BeforeClass
- public static void createLibJar() throws Exception {
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
- .compile();
- libJars.put(targetVersion, baseLibJar);
- }
- }
-
@Test
public void smokeTest() throws Exception {
- Path libJar = libJars.get(targetVersion);
+ Path libJar = libJars.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
@@ -98,7 +89,7 @@
.compile();
testForJvm()
.addRunClasspathFiles(
- ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -108,7 +99,7 @@
public void testMetadataForLib() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addProgramFiles(libJars.get(targetVersion))
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
/// Keep the annotations
.addKeepClassAndMembersRules(PKG_LIB + ".AnnoWithClassAndEnum")
.addKeepClassAndMembersRules(PKG_LIB + ".AnnoWithClassArr")
@@ -134,14 +125,14 @@
.inspect(this::inspect)
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
.compile();
testForJvm()
.addRunClasspathFiles(
- ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
.addProgramFiles(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED.replace(FOO_ORIGINAL_NAME, FOO_FINAL_NAME));
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
index 14cbe0b..0ff40ff 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteAnonymousTest.java
@@ -4,10 +4,11 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -17,9 +18,6 @@
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -29,45 +27,36 @@
private final String EXPECTED = "foo";
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteAnonymousTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+ private static final KotlinCompileMemoizer libJars =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/anonymous_lib", "lib"));
private final TestParameters parameters;
- @BeforeClass
- public static void createLibJar() throws Exception {
- String baseLibFolder = PKG_PREFIX + "/anonymous_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(baseLibFolder, "lib"))
- .compile();
- libJars.put(targetVersion, baseLibJar);
- }
- }
-
@Test
public void smokeTest() throws Exception {
- Path libJar = libJars.get(targetVersion);
+ Path libJar = libJars.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/anonymous_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".anonymous_app.MainKt")
.assertSuccessWithOutputLines(EXPECTED);
@@ -77,8 +66,8 @@
public void testMetadataForLib() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(libJars.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
.addKeepAllClassesRuleWithAllowObfuscation()
.addKeepRules("-keep class " + PKG + ".anonymous_lib.Test$A { *; }")
.addKeepRules("-keep class " + PKG + ".anonymous_lib.Test { *; }")
@@ -91,13 +80,13 @@
.inspect(this::inspect)
.writeToZip();
Path main =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/anonymous_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(main)
.run(parameters.getRuntime(), PKG + ".anonymous_app.MainKt")
.assertSuccessWithOutputLines(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
index 06d2636..2c2ae83 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteBoxedTypesTest.java
@@ -4,13 +4,14 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertNotNull;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNull;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -23,12 +24,9 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
import java.util.concurrent.ExecutionException;
import kotlinx.metadata.jvm.KotlinClassHeader;
import kotlinx.metadata.jvm.KotlinClassMetadata;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -39,44 +37,35 @@
private final String EXPECTED =
StringUtils.lines("false", "0", "a", "0.042", "0.42", "42", "442", "1", "2", "42", "42");
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteBoxedTypesTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+ private static final KotlinCompileMemoizer libJars =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_lib", "lib"));
private final TestParameters parameters;
- @BeforeClass
- public static void createLibJar() throws Exception {
- String baseLibFolder = PKG_PREFIX + "/box_primitives_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(baseLibFolder, "lib"))
- .compile();
- libJars.put(targetVersion, baseLibJar);
- }
- }
-
@Test
public void smokeTest() throws Exception {
- Path libJar = libJars.get(targetVersion);
+ Path libJar = libJars.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".box_primitives_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -84,9 +73,9 @@
@Test
public void smokeTestReflection() throws Exception {
- Path libJar = libJars.get(targetVersion);
+ Path libJar = libJars.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_app", "main_reflect"))
.setOutputPath(temp.newFolder().toPath())
@@ -94,7 +83,7 @@
testForJvm()
.addVmArguments("-ea")
.addRunClasspathFiles(
- ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".box_primitives_app.Main_reflectKt")
.assertSuccessWithOutput(EXPECTED);
@@ -104,8 +93,8 @@
public void testMetadataForLib() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(libJars.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
.addKeepAllClassesRule()
.addKeepAttributes(
ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS,
@@ -116,14 +105,14 @@
.inspect(this::inspect)
.writeToZip();
Path main =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
.addRunClasspathFiles(
- ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
.addClasspath(main)
.run(parameters.getRuntime(), PKG + ".box_primitives_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -132,7 +121,8 @@
private void inspect(CodeInspector inspector) throws IOException, ExecutionException {
// Since this has a keep-all classes rule, we should just assert that the meta-data is equal to
// the original one.
- CodeInspector stdLibInspector = new CodeInspector(libJars.get(targetVersion));
+ CodeInspector stdLibInspector =
+ new CodeInspector(libJars.getForConfiguration(kotlinc, targetVersion));
for (FoundClassSubject clazzSubject : stdLibInspector.allClasses()) {
ClassSubject r8Clazz = inspector.clazz(clazzSubject.getOriginalName());
assertThat(r8Clazz, isPresent());
@@ -159,8 +149,8 @@
public void testMetadataForReflect() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(libJars.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
.addKeepAllClassesRule()
.addKeepAttributes(
ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS,
@@ -170,7 +160,7 @@
.compile()
.writeToZip();
Path main =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_app", "main_reflect"))
.setOutputPath(temp.newFolder().toPath())
@@ -178,7 +168,7 @@
testForJvm()
.addVmArguments("-ea")
.addRunClasspathFiles(
- ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
.addClasspath(main)
.run(parameters.getRuntime(), PKG + ".box_primitives_app.Main_reflectKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
index 1ebdddb..56fd483 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineAnonFunctionTest.java
@@ -4,8 +4,9 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -13,9 +14,6 @@
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -27,45 +25,37 @@
private static final String PKG_LIB = PKG + ".crossinline_anon_lib";
private static final String PKG_APP = PKG + ".crossinline_anon_app";
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteCrossinlineAnonFunctionTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+ private static final KotlinCompileMemoizer libJars =
+ getCompileMemoizer(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
private final TestParameters parameters;
- @BeforeClass
- public static void createLibJar() throws Exception {
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
- .compile();
- libJars.put(targetVersion, baseLibJar);
- }
- }
-
@Test
public void smokeTest() throws Exception {
- Path libJar = libJars.get(targetVersion);
+ Path libJar = libJars.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -75,19 +65,19 @@
public void testMetadataForLib() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addProgramFiles(libJars.get(targetVersion))
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
.addKeepAllClassesRule()
.addKeepAllAttributes()
.compile()
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addProgramFiles(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
index ce26b77..b8c5ac2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteCrossinlineConcreteFunctionTest.java
@@ -4,8 +4,9 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -13,9 +14,6 @@
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -27,45 +25,37 @@
private static final String PKG_LIB = PKG + ".crossinline_concrete_lib";
private static final String PKG_APP = PKG + ".crossinline_concrete_app";
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteCrossinlineConcreteFunctionTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+ private static final KotlinCompileMemoizer libJars =
+ getCompileMemoizer(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
private final TestParameters parameters;
- @BeforeClass
- public static void createLibJar() throws Exception {
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
- .compile();
- libJars.put(targetVersion, baseLibJar);
- }
- }
-
@Test
public void smokeTest() throws Exception {
- Path libJar = libJars.get(targetVersion);
+ Path libJar = libJars.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -75,20 +65,20 @@
public void testMetadataForLib() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addProgramFiles(libJars.get(targetVersion))
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
.addKeepAllClassesRule()
.addKeepAllAttributes()
.compile()
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
index badbf02..d71248e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDelegatedPropertyTest.java
@@ -4,8 +4,9 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -15,9 +16,6 @@
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -35,38 +33,31 @@
"null",
"New value has been read in CustomDelegate from 'x'");
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteDelegatedPropertyTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
private final TestParameters parameters;
- private static Map<KotlinTargetVersion, Path> jars = new HashMap<>();
-
- @BeforeClass
- public static void createJar() throws Exception {
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
- .compile();
- jars.put(targetVersion, baseLibJar);
- }
- }
+ private static final KotlinCompileMemoizer jars =
+ getCompileMemoizer(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"));
@Test
public void smokeTest() throws Exception {
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar())
- .addClasspath(jars.get(targetVersion))
+ .addRunClasspathFiles(
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc))
+ .addClasspath(jars.getForConfiguration(kotlinc, targetVersion))
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED_MAIN);
}
@@ -76,17 +67,20 @@
public void testMetadataForLib() throws Exception {
Path outputJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(jars.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(jars.getForConfiguration(kotlinc, targetVersion))
.addKeepAllClassesRule()
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
.compile()
.inspect(
inspector ->
- assertEqualMetadata(new CodeInspector(jars.get(targetVersion)), inspector))
+ assertEqualMetadata(
+ new CodeInspector(jars.getForConfiguration(kotlinc, targetVersion)),
+ inspector))
.writeToZip();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar())
+ .addRunClasspathFiles(
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc))
.addClasspath(outputJar)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED_MAIN);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java
index a8fcf61..15112f6 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDependentKeep.java
@@ -4,10 +4,12 @@
package com.android.tools.r8.kotlin.metadata;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -25,24 +27,26 @@
@RunWith(Parameterized.class)
public class MetadataRewriteDependentKeep extends KotlinMetadataTestBase {
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
private final TestParameters parameters;
public MetadataRewriteDependentKeep(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
@Test
public void testR8() throws CompilationFailedException, IOException, ExecutionException {
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.setMinApi(parameters.getApiLevel())
.addKeepKotlinMetadata()
.addKeepRules(StringUtils.joinLines("-if class *.Metadata", "-keep class <1>.io.** { *; }"))
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
index 788e64b..fb4dab9 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteDoNotEmitValuesIfEmpty.java
@@ -4,9 +4,11 @@
package com.android.tools.r8.kotlin.metadata;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -27,24 +29,26 @@
private final Set<String> nullableFieldKeys = Sets.newHashSet("pn", "xs", "xi");
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
private final TestParameters parameters;
public MetadataRewriteDoNotEmitValuesIfEmpty(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
@Test
public void testKotlinStdLib() throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.setMinApi(parameters.getApiLevel())
.addKeepAllClassesRule()
.addKeepKotlinMetadata()
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
index d5b9fd0..ecaea79 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteFlexibleUpperBoundTest.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -12,6 +12,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -25,12 +26,9 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import java.util.concurrent.ExecutionException;
import kotlinx.metadata.KmFlexibleTypeUpperBound;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -41,44 +39,35 @@
private final String EXPECTED = StringUtils.lines("B.foo(): 42");
private final String PKG_LIB = PKG + ".flexible_upper_bound_lib";
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteFlexibleUpperBoundTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+ private static final KotlinCompileMemoizer libJars =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/flexible_upper_bound_lib", "lib"));
private final TestParameters parameters;
- @BeforeClass
- public static void createLibJar() throws Exception {
- String baseLibFolder = PKG_PREFIX + "/flexible_upper_bound_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(baseLibFolder, "lib"))
- .compile();
- libJars.put(targetVersion, baseLibJar);
- }
- }
-
@Test
public void smokeTest() throws Exception {
- Path libJar = libJars.get(targetVersion);
+ Path libJar = libJars.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/flexible_upper_bound_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".flexible_upper_bound_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -88,8 +77,8 @@
public void testMetadataForLib() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(libJars.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
// Allow renaming A to ensure that we rename in the flexible upper bound type.
.addKeepRules("-keep,allowobfuscation class " + PKG_LIB + ".A { *; }")
.addKeepRules("-keep class " + PKG_LIB + ".B { *; }")
@@ -103,14 +92,14 @@
.inspect(this::inspect)
.writeToZip();
Path main =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/flexible_upper_bound_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
.addRunClasspathFiles(
- ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
.addClasspath(main)
.run(parameters.getRuntime(), PKG + ".flexible_upper_bound_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
index 2103f0d..09d3af7 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInClasspathTypeTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -11,6 +11,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -23,10 +24,7 @@
import com.android.tools.r8.utils.codeinspector.KmPackageSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -37,54 +35,45 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInClasspathTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> baseLibJarMap = new HashMap<>();
- private static final Map<KotlinTargetVersion, Path> extLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String baseLibFolder = PKG_PREFIX + "/classpath_lib_base";
- String extLibFolder = PKG_PREFIX + "/classpath_lib_ext";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(baseLibFolder, "itf"))
- .compile();
- Path extLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addClasspathFiles(baseLibJar)
- .addSourceFiles(getKotlinFileInTest(extLibFolder, "impl"))
- .compile();
- baseLibJarMap.put(targetVersion, baseLibJar);
- extLibJarMap.put(targetVersion, extLibJar);
- }
- }
+ private static final KotlinCompileMemoizer baseLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/classpath_lib_base", "itf"));
+ private static final KotlinCompileMemoizer extLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/classpath_lib_ext", "impl"))
+ .configure(
+ kotlinCompilerTool -> {
+ kotlinCompilerTool.addClasspathFiles(
+ baseLibJarMap.getForConfiguration(
+ kotlinCompilerTool.getCompiler(), kotlinCompilerTool.getTargetVersion()));
+ });
@Test
public void smokeTest() throws Exception {
- Path baseLibJar = baseLibJarMap.get(targetVersion);
- Path extLibJar = extLibJarMap.get(targetVersion);
+ Path baseLibJar = baseLibJarMap.getForConfiguration(kotlinc, targetVersion);
+ Path extLibJar = extLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(baseLibJar, extLibJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/classpath_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), baseLibJar, extLibJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), baseLibJar, extLibJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".classpath_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -92,11 +81,11 @@
@Test
public void testMetadataInClasspathType_renamed() throws Exception {
- Path baseLibJar = baseLibJarMap.get(targetVersion);
+ Path baseLibJar = baseLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(baseLibJar, ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(extLibJarMap.get(targetVersion))
+ .addClasspathFiles(baseLibJar, ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(extLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep the Extra class and its interface (which has the method).
.addKeepRules("-keep class **.Extra")
// Keep Super, but allow minification.
@@ -110,14 +99,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(baseLibJar, libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/classpath_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), baseLibJar, libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), baseLibJar, libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".classpath_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
index 4c49518..d025713 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInCompanionTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -12,6 +12,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -25,10 +26,7 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -46,45 +44,36 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInCompanionTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> companionLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String companionLibFolder = PKG_PREFIX + "/companion_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path companionLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(companionLibFolder, "lib"))
- .compile();
- companionLibJarMap.put(targetVersion, companionLibJar);
- }
- }
+ private static final KotlinCompileMemoizer companionLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/companion_lib", "lib"));
@Test
public void smokeTest() throws Exception {
- Path libJar = companionLibJarMap.get(targetVersion);
+ Path libJar = companionLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/companion_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".companion_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -94,8 +83,8 @@
public void testMetadataInCompanion_kept() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(companionLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(companionLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep everything
.addKeepRules("-keep class **.companion_lib.** { *; }")
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
@@ -109,14 +98,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/companion_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".companion_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -126,8 +115,8 @@
public void testMetadataInCompanion_renamed() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(companionLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(companionLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep the B class and its interface (which has the doStuff method).
.addKeepRules("-keep class **.B")
// Property in companion with @JvmField is defined in the host class, without accessors.
@@ -151,14 +140,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/companion_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".companion_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
index 4f8b4a4..ac363d4 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionFunctionTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -13,6 +13,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -28,10 +29,7 @@
import com.android.tools.r8.utils.codeinspector.KmValueParameterSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -43,45 +41,36 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInExtensionFunctionTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> extLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String extLibFolder = PKG_PREFIX + "/extension_function_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path extLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(extLibFolder, "B"))
- .compile();
- extLibJarMap.put(targetVersion, extLibJar);
- }
- }
+ private static final KotlinCompileMemoizer extLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/extension_function_lib", "B"));
@Test
public void smokeTest() throws Exception {
- Path libJar = extLibJarMap.get(targetVersion);
+ Path libJar = extLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/extension_function_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".extension_function_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -92,7 +81,7 @@
public void testMetadataInExtensionFunction_merged() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addProgramFiles(extLibJarMap.get(targetVersion))
+ .addProgramFiles(extLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep the B class and its interface (which has the doStuff method).
.addKeepRules("-keep class **.B")
.addKeepRules("-keep class **.I { <methods>; }")
@@ -108,14 +97,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/extension_function_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".extension_function_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -143,8 +132,8 @@
public void testMetadataInExtensionFunction_renamed() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(extLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(extLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep the B class and its interface (which has the doStuff method).
.addKeepRules("-keep class **.B")
.addKeepRules("-keep class **.I { <methods>; }")
@@ -162,14 +151,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/extension_function_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".extension_function_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
index 9e81bf2..327ec34 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInExtensionPropertyTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionProperty;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -14,6 +14,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -27,10 +28,7 @@
import com.android.tools.r8.utils.codeinspector.KmPropertySubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -42,45 +40,36 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInExtensionPropertyTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> extLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String extLibFolder = PKG_PREFIX + "/extension_property_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path extLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(extLibFolder, "B"))
- .compile();
- extLibJarMap.put(targetVersion, extLibJar);
- }
- }
+ private static final KotlinCompileMemoizer extLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/extension_property_lib", "B"));
@Test
public void smokeTest() throws Exception {
- Path libJar = extLibJarMap.get(targetVersion);
+ Path libJar = extLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/extension_property_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".extension_property_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -91,7 +80,7 @@
public void testMetadataInExtensionProperty_merged() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addProgramFiles(extLibJarMap.get(targetVersion))
+ .addProgramFiles(extLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep the B class and its interface (which has the doStuff method).
.addKeepRules("-keep class **.B")
.addKeepRules("-keep class **.I { <methods>; }")
@@ -104,14 +93,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/extension_property_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".extension_property_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -151,8 +140,8 @@
public void testMetadataInExtensionProperty_renamed() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(extLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(extLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep the B class and its interface (which has the doStuff method).
.addKeepRules("-keep class **.B")
.addKeepRules("-keep class **.I { <methods>; }")
@@ -167,14 +156,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/extension_property_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".extension_property_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
index dcb6dbe..91ed797 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -13,6 +13,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -26,10 +27,7 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -41,45 +39,36 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0} target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInFunctionTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> funLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String funLibFolder = PKG_PREFIX + "/function_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path funLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(funLibFolder, "B"))
- .compile();
- funLibJarMap.put(targetVersion, funLibJar);
- }
- }
+ private static final KotlinCompileMemoizer funLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/function_lib", "B"));
@Test
public void smokeTest() throws Exception {
- Path libJar = funLibJarMap.get(targetVersion);
+ Path libJar = funLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/function_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".function_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -90,7 +79,7 @@
public void testMetadataInFunction_merged() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addProgramFiles(funLibJarMap.get(targetVersion))
+ .addProgramFiles(funLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep the B class and its interface (which has the doStuff method).
.addKeepRules("-keep class **.B")
.addKeepRules("-keep class **.I { <methods>; }")
@@ -102,14 +91,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/function_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".function_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -148,8 +137,8 @@
public void testMetadataInFunction_renamed() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(funLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(funLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep the B class and its interface (which has the doStuff method).
.addKeepRules("-keep class **.B")
.addKeepRules("-keep class **.I { <methods>; }")
@@ -163,14 +152,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/function_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".function_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java
index 4cd9b6a..c9210a1 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithDefaultValueTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -12,6 +12,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -27,10 +28,7 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -41,45 +39,36 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInFunctionWithDefaultValueTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> defaultValueLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String default_valueLibFolder = PKG_PREFIX + "/default_value_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path default_valueLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(default_valueLibFolder, "lib"))
- .compile();
- defaultValueLibJarMap.put(targetVersion, default_valueLibJar);
- }
- }
+ private static final KotlinCompileMemoizer defaultValueLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/default_value_lib", "lib"));
@Test
public void smokeTest() throws Exception {
- Path libJar = defaultValueLibJarMap.get(targetVersion);
+ Path libJar = defaultValueLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/default_value_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".default_value_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -89,8 +78,9 @@
public void testMetadataInFunctionWithDefaultValue() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addLibraryFiles(ToolHelper.getJava8RuntimeJar(), ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(defaultValueLibJarMap.get(targetVersion))
+ .addLibraryFiles(
+ ToolHelper.getJava8RuntimeJar(), ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(defaultValueLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep LibKt and applyMap function, along with applyMap$default
.addKeepRules("-keep class **.LibKt { *** applyMap*(...); }")
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
@@ -102,14 +92,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/default_value_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".default_value_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
index 0914a23..a65c4b9 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInFunctionWithVarargTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -13,6 +13,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -28,10 +29,7 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -42,45 +40,36 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInFunctionWithVarargTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> varargLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String varargLibFolder = PKG_PREFIX + "/vararg_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path varargLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(varargLibFolder, "lib"))
- .compile();
- varargLibJarMap.put(targetVersion, varargLibJar);
- }
- }
+ private static final KotlinCompileMemoizer varargLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/vararg_lib", "lib"));
@Test
public void smokeTest() throws Exception {
- Path libJar = varargLibJarMap.get(targetVersion);
+ Path libJar = varargLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/vararg_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".vararg_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -90,8 +79,8 @@
public void testMetadataInFunctionWithVararg() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(varargLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(varargLibJarMap.getForConfiguration(kotlinc, targetVersion))
// keep SomeClass#foo, since there is a method reference in the app.
.addKeepRules("-keep class **.SomeClass { *** foo(...); }")
// Keep LibKt, along with bar function.
@@ -105,14 +94,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/vararg_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".vararg_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java
index 159bf66..e635091 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInLibraryTypeTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static org.hamcrest.CoreMatchers.anyOf;
@@ -11,6 +11,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -21,9 +22,6 @@
import com.android.tools.r8.utils.codeinspector.KmPackageSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -34,54 +32,51 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInLibraryTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> baseLibJarMap = new HashMap<>();
- private static final Map<KotlinTargetVersion, Path> extLibJarMap = new HashMap<>();
- private static final Map<KotlinTargetVersion, Path> appJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String baseLibFolder = PKG_PREFIX + "/libtype_lib_base";
- String extLibFolder = PKG_PREFIX + "/libtype_lib_ext";
- String appFolder = PKG_PREFIX + "/libtype_app";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(baseLibFolder, "base"))
- .compile();
- Path extLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addClasspathFiles(baseLibJar)
- .addSourceFiles(getKotlinFileInTest(extLibFolder, "ext"))
- .compile();
- Path appJar =
- kotlinc(KOTLINC, targetVersion)
- .addClasspathFiles(baseLibJar)
- .addClasspathFiles(extLibJar)
- .addSourceFiles(getKotlinFileInTest(appFolder, "main"))
- .compile();
- baseLibJarMap.put(targetVersion, baseLibJar);
- extLibJarMap.put(targetVersion, extLibJar);
- appJarMap.put(targetVersion, appJar);
- }
- }
+ private static final KotlinCompileMemoizer baseLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/libtype_lib_base", "base"));
+ private static final KotlinCompileMemoizer extLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/libtype_lib_ext", "ext"))
+ .configure(
+ kotlinCompilerTool -> {
+ kotlinCompilerTool.addClasspathFiles(
+ baseLibJarMap.getForConfiguration(
+ kotlinCompilerTool.getCompiler(), kotlinCompilerTool.getTargetVersion()));
+ });
+ private static final KotlinCompileMemoizer appJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/libtype_app", "main"))
+ .configure(
+ kotlinCompilerTool -> {
+ kotlinCompilerTool.addClasspathFiles(
+ baseLibJarMap.getForConfiguration(
+ kotlinCompilerTool.getCompiler(), kotlinCompilerTool.getTargetVersion()));
+ kotlinCompilerTool.addClasspathFiles(
+ extLibJarMap.getForConfiguration(
+ kotlinCompilerTool.getCompiler(), kotlinCompilerTool.getTargetVersion()));
+ });
@Test
public void smokeTest() throws Exception {
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), baseLibJarMap.get(targetVersion))
- .addClasspath(extLibJarMap.get(targetVersion), appJarMap.get(targetVersion))
+ .addRunClasspathFiles(
+ ToolHelper.getKotlinStdlibJar(kotlinc),
+ baseLibJarMap.getForConfiguration(kotlinc, targetVersion))
+ .addClasspath(
+ extLibJarMap.getForConfiguration(kotlinc, targetVersion),
+ appJarMap.getForConfiguration(kotlinc, targetVersion))
.run(parameters.getRuntime(), PKG + ".libtype_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
}
@@ -93,7 +88,9 @@
testForR8(parameters.getBackend())
// Intentionally not providing baseLibJar as lib file nor classpath file.
.addClasspathFiles()
- .addProgramFiles(extLibJarMap.get(targetVersion), appJarMap.get(targetVersion))
+ .addProgramFiles(
+ extLibJarMap.getForConfiguration(kotlinc, targetVersion),
+ appJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep Ext extension method which requires metadata to be called with Kotlin syntax
// from other kotlin code.
.addKeepRules("-keep class **.ExtKt { <methods>; }")
@@ -112,7 +109,9 @@
.writeToZip();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), baseLibJarMap.get(targetVersion))
+ .addRunClasspathFiles(
+ ToolHelper.getKotlinStdlibJar(kotlinc),
+ baseLibJarMap.getForConfiguration(kotlinc, targetVersion))
.addClasspath(out)
.run(parameters.getRuntime(), main)
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java
index 45a419d..8adeb48 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInMultifileClassTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -16,6 +16,7 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -31,11 +32,8 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import kotlinx.metadata.jvm.KotlinClassMetadata;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -46,47 +44,38 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInMultifileClassTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> multifileLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String multifileLibFolder = PKG_PREFIX + "/multifileclass_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path multifileLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- getKotlinFileInTest(multifileLibFolder, "signed"),
- getKotlinFileInTest(multifileLibFolder, "unsigned"))
- .compile();
- multifileLibJarMap.put(targetVersion, multifileLibJar);
- }
- }
+ private static final KotlinCompileMemoizer multifileLibJarMap =
+ getCompileMemoizer(
+ getKotlinFileInTest(PKG_PREFIX + "/multifileclass_lib", "signed"),
+ getKotlinFileInTest(PKG_PREFIX + "/multifileclass_lib", "unsigned"));
@Test
public void smokeTest() throws Exception {
- Path libJar = multifileLibJarMap.get(targetVersion);
+ Path libJar = multifileLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/multifileclass_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".multifileclass_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -96,8 +85,8 @@
public void testMetadataInMultifileClass_merged() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(multifileLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(multifileLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep UtilKt#comma*Join*(). Let R8 optimize (inline) others, such as joinOf*(String).
.addKeepRules("-keep class **.UtilKt")
.addKeepRules("-keepclassmembers class * { ** comma*Join*(...); }")
@@ -107,7 +96,7 @@
.writeToZip();
ProcessResult kotlinTestCompileResult =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/multifileclass_app", "main"))
.setOutputPath(temp.newFolder().toPath())
@@ -137,8 +126,8 @@
public void testMetadataInMultifileClass_renamed() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(multifileLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(multifileLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep UtilKt#comma*Join*().
.addKeepRules("-keep class **.UtilKt")
.addKeepRules("-keep,allowobfuscation class **.UtilKt__SignedKt")
@@ -151,7 +140,7 @@
.writeToZip();
ProcessResult kotlinTestCompileResult =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/multifileclass_app", "main"))
.setOutputPath(temp.newFolder().toPath())
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
index eada4da..8bb4603 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInNestedClassTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -12,6 +12,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -22,9 +23,6 @@
import com.android.tools.r8.utils.codeinspector.KmClassSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -36,45 +34,36 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInNestedClassTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> nestedLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String nestedLibFolder = PKG_PREFIX + "/nested_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path nestedLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(nestedLibFolder, "lib"))
- .compile();
- nestedLibJarMap.put(targetVersion, nestedLibJar);
- }
- }
+ private static final KotlinCompileMemoizer nestedLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/nested_lib", "lib"));
@Test
public void smokeTest() throws Exception {
- Path libJar = nestedLibJarMap.get(targetVersion);
+ Path libJar = nestedLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/nested_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".nested_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -84,8 +73,8 @@
public void testMetadataInNestedClass() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(nestedLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(nestedLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep the Outer class and delegations.
.addKeepRules("-keep class **.Outer { <init>(...); *** delegate*(...); }")
// Keep Inner to check the hierarchy.
@@ -100,14 +89,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/nested_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".nested_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
index b4ae665..a2a85c3 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInParameterTypeTest.java
@@ -3,13 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -20,10 +21,7 @@
import com.android.tools.r8.utils.codeinspector.KmClassSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -34,45 +32,36 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInParameterTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> parameterTypeLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String parameterTypeLibFolder = PKG_PREFIX + "/parametertype_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path parameterTypeLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(parameterTypeLibFolder, "lib"))
- .compile();
- parameterTypeLibJarMap.put(targetVersion, parameterTypeLibJar);
- }
- }
+ private static final KotlinCompileMemoizer parameterTypeLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/parametertype_lib", "lib"));
@Test
public void smokeTest() throws Exception {
- Path libJar = parameterTypeLibJarMap.get(targetVersion);
+ Path libJar = parameterTypeLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/parametertype_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".parametertype_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -82,8 +71,8 @@
public void testMetadataInParameterType_renamed() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(parameterTypeLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(parameterTypeLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep non-private members of Impl
.addKeepRules("-keep public class **.Impl { !private *; }")
// Keep Itf, but allow minification.
@@ -94,14 +83,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/parametertype_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".parametertype_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
index c479093..d012f10 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionProperty;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -14,6 +14,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -27,9 +28,6 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -40,38 +38,29 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInPropertyTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> propertyTypeLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String propertyTypeLibFolder = PKG_PREFIX + "/fragile_property_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path propertyTypeLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(propertyTypeLibFolder, "lib"))
- .compile();
- propertyTypeLibJarMap.put(targetVersion, propertyTypeLibJar);
- }
- }
+ private static final KotlinCompileMemoizer propertyTypeLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/fragile_property_lib", "lib"));
@Test
public void smokeTest_getterApp() throws Exception {
- Path libJar = propertyTypeLibJarMap.get(targetVersion);
+ Path libJar = propertyTypeLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(PKG_PREFIX + "/fragile_property_only_getter", "getter_user"))
@@ -79,7 +68,7 @@
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".fragile_property_only_getter.Getter_userKt")
.assertSuccessWithOutput(EXPECTED_GETTER);
@@ -89,8 +78,8 @@
public void testMetadataInProperty_getterOnly() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(propertyTypeLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(propertyTypeLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep property getters
.addKeepRules("-keep class **.Person { <init>(...); }")
.addKeepRules("-keepclassmembers class **.Person { *** get*(); }")
@@ -100,7 +89,7 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(PKG_PREFIX + "/fragile_property_only_getter", "getter_user"))
@@ -108,7 +97,7 @@
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".fragile_property_only_getter.Getter_userKt")
.assertSuccessWithOutput(EXPECTED_GETTER);
@@ -159,10 +148,10 @@
@Test
public void smokeTest_setterApp() throws Exception {
- Path libJar = propertyTypeLibJarMap.get(targetVersion);
+ Path libJar = propertyTypeLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(PKG_PREFIX + "/fragile_property_only_setter", "setter_user"))
@@ -170,7 +159,7 @@
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".fragile_property_only_setter.Setter_userKt")
.assertSuccessWithOutputLines();
@@ -180,8 +169,8 @@
public void testMetadataInProperty_setterOnly() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(propertyTypeLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(propertyTypeLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep property setters (and users)
.addKeepRules("-keep class **.Person { <init>(...); }")
.addKeepRules("-keepclassmembers class **.Person { void set*(...); }")
@@ -195,7 +184,7 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(PKG_PREFIX + "/fragile_property_only_setter", "setter_user"))
@@ -203,7 +192,7 @@
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".fragile_property_only_setter.Setter_userKt")
.assertSuccessWithOutputLines();
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
index eb9ff61..9641f64 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInPropertyTypeTest.java
@@ -3,13 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -20,10 +21,7 @@
import com.android.tools.r8.utils.codeinspector.KmClassSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -34,45 +32,36 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInPropertyTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> propertyTypeLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String propertyTypeLibFolder = PKG_PREFIX + "/propertytype_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path propertyTypeLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(propertyTypeLibFolder, "lib"))
- .compile();
- propertyTypeLibJarMap.put(targetVersion, propertyTypeLibJar);
- }
- }
+ private static final KotlinCompileMemoizer propertyTypeLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/propertytype_lib", "lib"));
@Test
public void smokeTest() throws Exception {
- Path libJar = propertyTypeLibJarMap.get(targetVersion);
+ Path libJar = propertyTypeLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/propertytype_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".propertytype_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -82,8 +71,8 @@
public void testMetadataInProperty_renamed() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(propertyTypeLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(propertyTypeLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep non-private members of Impl
.addKeepRules("-keep public class **.Impl { !private *; }")
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
@@ -92,14 +81,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/propertytype_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".propertytype_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java
index 8be744d..a4a3a68 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInRenamedTypeTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.DescriptorUtils.getDescriptorFromKotlinClassifier;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -12,6 +12,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -20,11 +21,7 @@
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.KmClassSubject;
-import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -36,47 +33,39 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withAllRuntimesAndApiLevels().build(), KotlinTargetVersion.values());
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInRenamedTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> annoJarMap = new HashMap<>();
- private static final Map<KotlinTargetVersion, Path> inputJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createInputJar() throws Exception {
- String inputFolder = PKG_PREFIX + "/anno";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path annoJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(inputFolder, "Anno"))
- .compile();
- Path inputJar =
- kotlinc(KOTLINC, targetVersion)
- .addClasspathFiles(annoJar)
- .addSourceFiles(getKotlinFileInTest(inputFolder, "main"))
- .compile();
- annoJarMap.put(targetVersion, annoJar);
- inputJarMap.put(targetVersion, inputJar);
- }
- }
+ private static final KotlinCompileMemoizer annoJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/anno", "Anno"));
+ private static final KotlinCompileMemoizer inputJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/anno", "main"))
+ .configure(
+ kotlinCompilerTool -> {
+ kotlinCompilerTool.addClasspathFiles(
+ annoJarMap.getForConfiguration(
+ kotlinCompilerTool.getCompiler(), kotlinCompilerTool.getTargetVersion()));
+ });
@Test
public void testR8_kotlinStdlibAsLib() throws Exception {
testForR8(parameters.getBackend())
.addLibraryFiles(
- annoJarMap.get(targetVersion),
+ annoJarMap.getForConfiguration(kotlinc, targetVersion),
ToolHelper.getJava8RuntimeJar(),
- ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(inputJarMap.get(targetVersion))
+ ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(inputJarMap.getForConfiguration(kotlinc, targetVersion))
.addKeepRules(OBFUSCATE_RENAMED, KEEP_KEPT)
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
.compile()
@@ -86,8 +75,10 @@
@Test
public void testR8_kotlinStdlibAsClassPath() throws Exception {
testForR8(parameters.getBackend())
- .addClasspathFiles(annoJarMap.get(targetVersion), ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(inputJarMap.get(targetVersion))
+ .addClasspathFiles(
+ annoJarMap.getForConfiguration(kotlinc, targetVersion),
+ ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(inputJarMap.getForConfiguration(kotlinc, targetVersion))
.addKeepRules(OBFUSCATE_RENAMED, KEEP_KEPT)
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
.compile()
@@ -97,8 +88,10 @@
@Test
public void testR8_kotlinStdlibAsProgramFile() throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(annoJarMap.get(targetVersion), ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(inputJarMap.get(targetVersion))
+ .addProgramFiles(
+ annoJarMap.getForConfiguration(kotlinc, targetVersion),
+ ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(inputJarMap.getForConfiguration(kotlinc, targetVersion))
.addKeepRules(OBFUSCATE_RENAMED, KEEP_KEPT)
.addKeepRules("-keep class **.Anno")
.addKeepKotlinMetadata()
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
index 47b0b82..9783f3b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInReturnTypeTest.java
@@ -3,13 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -20,10 +21,7 @@
import com.android.tools.r8.utils.codeinspector.KmClassSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -34,45 +32,36 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInReturnTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> returnTypeLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String returnTypeLibFolder = PKG_PREFIX + "/returntype_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path returnTypeLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(returnTypeLibFolder, "lib"))
- .compile();
- returnTypeLibJarMap.put(targetVersion, returnTypeLibJar);
- }
- }
+ private static final KotlinCompileMemoizer returnTypeLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/returntype_lib", "lib"));
@Test
public void smokeTest() throws Exception {
- Path libJar = returnTypeLibJarMap.get(targetVersion);
+ Path libJar = returnTypeLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/returntype_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".returntype_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -82,8 +71,8 @@
public void testMetadataInReturnType_renamed() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(returnTypeLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(returnTypeLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep non-private members of Impl
.addKeepRules("-keep public class **.Impl { !private *; }")
// Keep Itf, but allow minification.
@@ -94,14 +83,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/returntype_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".returntype_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java
index 3fb7b23..f33fc30 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassNestedTest.java
@@ -3,8 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -13,9 +14,6 @@
import com.android.tools.r8.utils.StringUtils;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -33,37 +31,29 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInSealedClassNestedTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> sealedLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path sealedLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "nested"))
- .compile();
- sealedLibJarMap.put(targetVersion, sealedLibJar);
- }
- }
+ private static final KotlinCompileMemoizer sealedLibJarMap =
+ getCompileMemoizer(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "nested"));
@Test
public void smokeTest() throws Exception {
- Path libJar = sealedLibJarMap.get(targetVersion);
+ Path libJar = sealedLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
@@ -71,7 +61,7 @@
.compile();
testForJvm()
.addRunClasspathFiles(
- ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -81,8 +71,8 @@
public void testMetadataInSealedClass_nested() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(sealedLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(sealedLibJarMap.getForConfiguration(kotlinc, targetVersion))
.addKeepAllClassesRule()
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
.addKeepAttributes(
@@ -90,7 +80,7 @@
.compile()
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
@@ -98,7 +88,7 @@
.compile();
testForJvm()
.addRunClasspathFiles(
- ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java
index 1bb1c44..2dbbc48 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSealedClassTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.DescriptorUtils.descriptorToJavaType;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -15,6 +15,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -28,9 +29,6 @@
import com.android.tools.r8.utils.codeinspector.KmPackageSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -41,45 +39,36 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInSealedClassTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> sealedLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String sealedLibFolder = PKG_PREFIX + "/sealed_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path sealedLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(sealedLibFolder, "lib"))
- .compile();
- sealedLibJarMap.put(targetVersion, sealedLibJar);
- }
- }
+ private static final KotlinCompileMemoizer sealedLibJarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/sealed_lib", "lib"));
@Test
public void smokeTest() throws Exception {
- Path libJar = sealedLibJarMap.get(targetVersion);
+ Path libJar = sealedLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/sealed_app", "valid"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".sealed_app.ValidKt")
.assertSuccessWithOutput(EXPECTED);
@@ -89,8 +78,8 @@
public void testMetadataInSealedClass_valid() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(sealedLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(sealedLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep the Expr class
.addKeepRules("-keep class **.Expr")
// Keep the extension function
@@ -103,14 +92,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/sealed_app", "valid"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".sealed_app.ValidKt")
.assertSuccessWithOutput(EXPECTED);
@@ -156,8 +145,8 @@
public void testMetadataInSealedClass_invalid() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(sealedLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(sealedLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep the Expr class
.addKeepRules("-keep class **.Expr")
// Keep the extension function
@@ -168,7 +157,7 @@
.writeToZip();
ProcessResult kotlinTestCompileResult =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFilesWithNonKtExtension(
temp, getFileInTest(PKG_PREFIX + "/sealed_app", "invalid.kt_txt"))
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
index 578a7ec..9b0da43 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInSuperTypeTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -11,6 +11,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -21,10 +22,7 @@
import com.android.tools.r8.utils.codeinspector.KmClassSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -35,47 +33,38 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInSuperTypeTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> superTypeLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String superTypeLibFolder = PKG_PREFIX + "/supertype_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path superTypeLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- getKotlinFileInTest(superTypeLibFolder, "impl"),
- getKotlinFileInTest(superTypeLibFolder + "/internal", "itf"))
- .compile();
- superTypeLibJarMap.put(targetVersion, superTypeLibJar);
- }
- }
+ private static final KotlinCompileMemoizer superTypeLibJarMap =
+ getCompileMemoizer(
+ getKotlinFileInTest(PKG_PREFIX + "/supertype_lib", "impl"),
+ getKotlinFileInTest(PKG_PREFIX + "/supertype_lib" + "/internal", "itf"));
@Test
public void smokeTest() throws Exception {
- Path libJar = superTypeLibJarMap.get(targetVersion);
+ Path libJar = superTypeLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/supertype_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".supertype_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -85,8 +74,8 @@
public void testMetadataInSupertype_merged() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(superTypeLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(superTypeLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep non-private members except for ones in `internal` definitions.
.addKeepRules("-keep public class !**.internal.**, * { !private *; }")
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
@@ -95,14 +84,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/supertype_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".supertype_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -130,8 +119,8 @@
public void testMetadataInSupertype_renamed() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(superTypeLibJarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(superTypeLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep non-private members except for ones in `internal` definitions.
.addKeepRules("-keep public class !**.internal.**, * { !private *; }")
// Keep `internal` definitions, but allow minification.
@@ -142,14 +131,14 @@
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/supertype_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".supertype_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
index ac4085f..edade6e 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeAliasTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isDexClass;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
@@ -13,6 +13,7 @@
import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -30,9 +31,6 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -63,40 +61,31 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInTypeAliasTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> typeAliasLibJarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String typeAliasLibFolder = PKG_PREFIX + "/typealias_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path typeAliasLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- getKotlinFileInTest(typeAliasLibFolder, "lib"),
- getKotlinFileInTest(typeAliasLibFolder, "lib_ext"))
- .compile();
- typeAliasLibJarMap.put(targetVersion, typeAliasLibJar);
- }
- }
+ private static final KotlinCompileMemoizer typeAliasLibJarMap =
+ getCompileMemoizer(
+ getKotlinFileInTest(PKG_PREFIX + "/typealias_lib", "lib"),
+ getKotlinFileInTest(PKG_PREFIX + "/typealias_lib", "lib_ext"));
@Test
public void smokeTest() throws Exception {
- Path libJar = typeAliasLibJarMap.get(targetVersion);
+ Path libJar = typeAliasLibJarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/typealias_app", "main"))
.setOutputPath(temp.newFolder().toPath())
@@ -104,7 +93,7 @@
testForJvm()
.addRunClasspathFiles(
- ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".typealias_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -116,8 +105,9 @@
String renamedSuperTypeName = "com.android.tools.r8.kotlin.metadata.typealias_lib.FooBar";
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar())
- .addProgramFiles(typeAliasLibJarMap.get(targetVersion))
+ .addClasspathFiles(
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc))
+ .addProgramFiles(typeAliasLibJarMap.getForConfiguration(kotlinc, targetVersion))
// Keep non-private members of Impl
.addKeepRules("-keep class **.Impl { !private *; }")
// Keep but allow obfuscation of types.
@@ -144,14 +134,14 @@
.writeToZip();
Path appJar =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/typealias_app", "main"))
.compile();
testForJvm()
.addRunClasspathFiles(
- ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
.addClasspath(appJar)
.run(parameters.getRuntime(), PKG + ".typealias_app.MainKt")
.assertSuccessWithOutput(EXPECTED.replace(superTypeName, renamedSuperTypeName));
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
index 52ae0b3..788abf2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInTypeArgumentsTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isDexClass;
import static com.android.tools.r8.utils.codeinspector.Matchers.isExtensionFunction;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
@@ -12,6 +12,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -30,12 +31,9 @@
import com.android.tools.r8.utils.codeinspector.KmValueParameterSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
import kotlinx.metadata.KmClassifier.TypeParameter;
import kotlinx.metadata.KmVariance;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -79,45 +77,36 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInTypeArgumentsTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static final Map<KotlinTargetVersion, Path> jarMap = new HashMap<>();
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- String typeAliasLibFolder = PKG_PREFIX + "/typeargument_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path typeAliasLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(typeAliasLibFolder, "lib"))
- .compile();
- jarMap.put(targetVersion, typeAliasLibJar);
- }
- }
+ private static final KotlinCompileMemoizer jarMap =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/typeargument_lib", "lib"));
@Test
public void smokeTest() throws Exception {
- Path libJar = jarMap.get(targetVersion);
+ Path libJar = jarMap.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/typeargument_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".typeargument_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -127,8 +116,8 @@
public void testMetadataInTypeAliasWithR8() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(jarMap.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(jarMap.getForConfiguration(kotlinc, targetVersion))
// Keep ClassThatWillBeObfuscated, but allow minification.
.addKeepRules("-keep,allowobfuscation class **ClassThatWillBeObfuscated")
.addKeepRules("-keepclassmembers class **ClassThatWillBeObfuscated { *; }")
@@ -148,12 +137,12 @@
.inspect(this::inspect)
.writeToZip();
Path mainJar =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/typeargument_app", "main"))
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(mainJar)
.run(parameters.getRuntime(), PKG + ".typeargument_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
index ffe5a51..133dd37 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteInlinePropertyTest.java
@@ -4,11 +4,12 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNull;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -21,13 +22,9 @@
import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.ExecutionException;
import junit.framework.TestCase;
import kotlinx.metadata.jvm.KotlinClassHeader;
import kotlinx.metadata.jvm.KotlinClassMetadata;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -36,46 +33,36 @@
public class MetadataRewriteInlinePropertyTest extends KotlinMetadataTestBase {
private final String EXPECTED = StringUtils.lines("true", "false", "false", "true");
- private final String PKG_LIB = PKG + ".inline_property_lib";
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewriteInlinePropertyTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+ private static final KotlinCompileMemoizer libJars =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/inline_property_lib", "lib"));
private final TestParameters parameters;
- @BeforeClass
- public static void createLibJar() throws Exception {
- String baseLibFolder = PKG_PREFIX + "/inline_property_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(baseLibFolder, "lib"))
- .compile();
- libJars.put(targetVersion, baseLibJar);
- }
- }
-
@Test
public void smokeTest() throws Exception {
- Path libJar = libJars.get(targetVersion);
+ Path libJar = libJars.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/inline_property_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG + ".inline_property_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -85,8 +72,8 @@
public void testMetadataForLib() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(libJars.get(targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
// Allow renaming A to ensure that we rename in the flexible upper bound type.
.addKeepAllClassesRule()
.addKeepAttributes(
@@ -98,21 +85,22 @@
.inspect(this::inspect)
.writeToZip();
Path main =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(getKotlinFileInTest(PKG_PREFIX + "/inline_property_app", "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
.addRunClasspathFiles(
- ToolHelper.getKotlinStdlibJar(), ToolHelper.getKotlinReflectJar(), libJar)
+ ToolHelper.getKotlinStdlibJar(kotlinc), ToolHelper.getKotlinReflectJar(kotlinc), libJar)
.addClasspath(main)
.run(parameters.getRuntime(), PKG + ".inline_property_app.MainKt")
.assertSuccessWithOutput(EXPECTED);
}
- private void inspect(CodeInspector inspector) throws IOException, ExecutionException {
- CodeInspector stdLibInspector = new CodeInspector(libJars.get(targetVersion));
+ private void inspect(CodeInspector inspector) throws IOException {
+ CodeInspector stdLibInspector =
+ new CodeInspector(libJars.getForConfiguration(kotlinc, targetVersion));
for (FoundClassSubject clazzSubject : stdLibInspector.allClasses()) {
ClassSubject r8Clazz = inspector.clazz(clazzSubject.getOriginalName());
assertThat(r8Clazz, isPresent());
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
index 2d3834b..83b8e62 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteJvmStaticTest.java
@@ -3,13 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.metadata.jvmstatic_app.MainJava;
@@ -23,8 +23,7 @@
import com.android.tools.r8.utils.codeinspector.KmPropertySubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.nio.file.Path;
-import java.nio.file.Paths;
-import org.junit.BeforeClass;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -39,39 +38,34 @@
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
- public static TestParametersCollection data() {
- return getTestParameters().withCfRuntimes().build();
+ @Parameterized.Parameters(name = "{0}, kotlinc: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(getTestParameters().withCfRuntimes().build(), getKotlinCompilers());
}
- public MetadataRewriteJvmStaticTest(TestParameters parameters) {
+ public MetadataRewriteJvmStaticTest(TestParameters parameters, KotlinCompiler kotlinc) {
// We are testing static methods on interfaces which requires java 8.
- super(KotlinTargetVersion.JAVA_8);
+ super(KotlinTargetVersion.JAVA_8, kotlinc);
this.parameters = parameters;
}
- private static Path kotlincLibJar = Paths.get("");
-
- @BeforeClass
- public static void createLibJar() throws Exception {
- kotlincLibJar =
- kotlinc(KOTLINC, KotlinTargetVersion.JAVA_8)
- .addSourceFiles(
- getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
- .compile();
- }
+ private static KotlinCompileMemoizer kotlincLibJar =
+ getCompileMemoizer(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
@Test
public void smokeTest() throws Exception {
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
- .addClasspathFiles(kotlincLibJar)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
+ .addClasspathFiles(kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), kotlincLibJar)
+ .addRunClasspathFiles(
+ ToolHelper.getKotlinStdlibJar(kotlinc),
+ kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
.addClasspath(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -80,7 +74,9 @@
@Test
public void smokeTestJava() throws Exception {
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), kotlincLibJar)
+ .addRunClasspathFiles(
+ ToolHelper.getKotlinStdlibJar(kotlinc),
+ kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
.addProgramClassFileData(MainJava.dump())
.run(parameters.getRuntime(), MainJava.class)
.assertSuccessWithOutput(EXPECTED);
@@ -90,7 +86,7 @@
public void testMetadata() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addProgramFiles(kotlincLibJar)
+ .addProgramFiles(kotlincLibJar.getForConfiguration(kotlinc, targetVersion))
.addKeepAllClassesRule()
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
.compile()
@@ -102,14 +98,14 @@
private void testKotlin(Path libJar) throws Exception {
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -117,7 +113,7 @@
private void testJava(Path libJar) throws Exception {
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addProgramClassFileData(MainJava.dump())
.run(parameters.getRuntime(), MainJava.class)
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java
index bb61374..40c7573 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepPathTest.java
@@ -4,12 +4,13 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestShrinkerBuilder;
import com.android.tools.r8.ToolHelper;
@@ -17,11 +18,7 @@
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -29,43 +26,36 @@
@RunWith(Parameterized.class)
public class MetadataRewriteKeepPathTest extends KotlinMetadataTestBase {
- @Parameterized.Parameters(name = "{0} target: {1}, keep: {2}")
+ @Parameterized.Parameters(name = "{0} target: {1}, kotlinc: {2}, keep: {3}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withCfRuntimes().build(),
KotlinTargetVersion.values(),
+ getKotlinCompilers(),
BooleanUtils.values());
}
- private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+ private static final KotlinCompileMemoizer libJars =
+ getCompileMemoizer(getKotlinFileInTest(PKG_PREFIX + "/box_primitives_lib", "lib"));
private static final String LIB_CLASS_NAME = PKG + ".box_primitives_lib.Test";
private final TestParameters parameters;
private final boolean keepMetadata;
public MetadataRewriteKeepPathTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, boolean keepMetadata) {
- super(targetVersion);
+ TestParameters parameters,
+ KotlinTargetVersion targetVersion,
+ KotlinCompiler kotlinc,
+ boolean keepMetadata) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
this.keepMetadata = keepMetadata;
}
- @BeforeClass
- public static void createLibJar() throws Exception {
- String baseLibFolder = PKG_PREFIX + "/box_primitives_lib";
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFileInTest(baseLibFolder, "lib"))
- .compile();
- libJars.put(targetVersion, baseLibJar);
- }
- }
-
@Test
public void testProgramPath() throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(libJars.get(targetVersion))
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addKeepRules("-keep class " + LIB_CLASS_NAME)
.applyIf(keepMetadata, TestShrinkerBuilder::addKeepKotlinMetadata)
.addKeepRuntimeVisibleAnnotations()
@@ -78,8 +68,8 @@
@Test
public void testClassPathPath() throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(libJars.get(targetVersion))
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addKeepRules("-keep class " + LIB_CLASS_NAME)
.addKeepRuntimeVisibleAnnotations()
.compile()
@@ -89,8 +79,8 @@
@Test
public void testLibraryPath() throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(libJars.get(targetVersion))
- .addLibraryFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
+ .addLibraryFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addLibraryFiles(ToolHelper.getJava8RuntimeJar())
.addKeepRules("-keep class " + LIB_CLASS_NAME)
.addKeepRuntimeVisibleAnnotations()
@@ -101,7 +91,7 @@
@Test
public void testMissing() throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(libJars.get(targetVersion))
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
.addKeepRules("-keep class " + LIB_CLASS_NAME)
.addKeepRuntimeVisibleAnnotations()
.compile()
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
index 0f80128..8c681bd 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewriteKeepTest.java
@@ -4,9 +4,11 @@
package com.android.tools.r8.kotlin.metadata;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -21,23 +23,26 @@
@RunWith(Parameterized.class)
public class MetadataRewriteKeepTest extends KotlinMetadataTestBase {
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
private final TestParameters parameters;
- public MetadataRewriteKeepTest(TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ public MetadataRewriteKeepTest(
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
@Test
public void testR8() throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.setMinApi(parameters.getApiLevel())
.addKeepKotlinMetadata()
.addKeepRules("-keep class kotlin.io.** { *; }")
@@ -49,7 +54,7 @@
@Test
public void testR8KeepIf() throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.setMinApi(parameters.getApiLevel())
.addKeepRules("-keep class kotlin.io.** { *; }")
.addKeepRules("-if class *", "-keep class kotlin.Metadata { *; }")
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
index 71d888c..3e62729 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePassThroughTest.java
@@ -4,6 +4,9 @@
package com.android.tools.r8.kotlin.metadata;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
+
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -17,24 +20,26 @@
@RunWith(Parameterized.class)
public class MetadataRewritePassThroughTest extends KotlinMetadataTestBase {
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
private final TestParameters parameters;
public MetadataRewritePassThroughTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
@Test
public void testKotlinStdLib() throws Exception {
testForR8(parameters.getBackend())
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.setMinApi(parameters.getApiLevel())
.addKeepAllClassesRule()
.addKeepKotlinMetadata()
@@ -42,6 +47,7 @@
.compile()
.inspect(
inspector ->
- assertEqualMetadata(new CodeInspector(ToolHelper.getKotlinStdlibJar()), inspector));
+ assertEqualMetadata(
+ new CodeInspector(ToolHelper.getKotlinStdlibJar(kotlinc)), inspector));
}
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
index 2a33484..39793cf 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataRewritePrunedObjectsTest.java
@@ -4,12 +4,13 @@
package com.android.tools.r8.kotlin.metadata;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertEquals;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -20,9 +21,6 @@
import com.android.tools.r8.utils.codeinspector.KmClassSubject;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -34,45 +32,37 @@
private static final String PKG_LIB = PKG + ".pruned_lib";
private static final String PKG_APP = PKG + ".pruned_app";
- private static Map<KotlinTargetVersion, Path> libJars = new HashMap<>();
+ private static final KotlinCompileMemoizer libJars =
+ getCompileMemoizer(
+ getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"));
private final TestParameters parameters;
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withCfRuntimes().build(), KotlinTargetVersion.values());
+ getTestParameters().withCfRuntimes().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
public MetadataRewritePrunedObjectsTest(
- TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- @BeforeClass
- public static void createLibJar() throws Exception {
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- Path baseLibJar =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_LIB), "lib"))
- .compile();
- libJars.put(targetVersion, baseLibJar);
- }
- }
-
@Test
public void smokeTest() throws Exception {
- Path libJar = libJars.get(targetVersion);
+ Path libJar = libJars.getForConfiguration(kotlinc, targetVersion);
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
.setOutputPath(temp.newFolder().toPath())
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addClasspath(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED);
@@ -82,7 +72,7 @@
public void testMetadataForLib() throws Exception {
Path libJar =
testForR8(parameters.getBackend())
- .addProgramFiles(libJars.get(targetVersion))
+ .addProgramFiles(libJars.getForConfiguration(kotlinc, targetVersion))
.addKeepRules("-keep class " + PKG_LIB + ".Sub { <init>(); *** kept(); }")
.addKeepRuntimeVisibleAnnotations()
.noMinification()
@@ -90,13 +80,13 @@
.inspect(this::checkPruned)
.writeToZip();
Path output =
- kotlinc(parameters.getRuntime().asCf(), KOTLINC, targetVersion)
+ kotlinc(parameters.getRuntime().asCf(), kotlinc, targetVersion)
.addClasspathFiles(libJar)
.addSourceFiles(
getKotlinFileInTest(DescriptorUtils.getBinaryNameFromJavaType(PKG_APP), "main"))
.compile();
testForJvm()
- .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(), libJar)
+ .addRunClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc), libJar)
.addProgramFiles(output)
.run(parameters.getRuntime(), PKG_APP + ".MainKt")
.assertSuccessWithOutput(EXPECTED);
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
index dec2ff2..168cbc5 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataStripTest.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.kotlin.metadata;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
@@ -10,6 +11,7 @@
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
@@ -27,28 +29,35 @@
public class MetadataStripTest extends KotlinMetadataTestBase {
private final TestParameters parameters;
+ private static final String FOLDER = "lambdas_jstyle_runnable";
- @Parameterized.Parameters(name = "{0} target: {1}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static Collection<Object[]> data() {
return buildParameters(
- getTestParameters().withAllRuntimesAndApiLevels().build(), KotlinTargetVersion.values());
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
- public MetadataStripTest(TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ public MetadataStripTest(
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
+ private static final KotlinCompileMemoizer compiledJars =
+ getCompileMemoizer(getKotlinFilesInResource(FOLDER), FOLDER)
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect());
+
@Test
public void testJstyleRunnable() throws Exception {
- final String folder = "lambdas_jstyle_runnable";
final String mainClassName = "lambdas_jstyle_runnable.MainKt";
final String implementer1ClassName = "lambdas_jstyle_runnable.Implementer1Kt";
R8TestRunResult result =
testForR8(parameters.getBackend())
- .addProgramFiles(getKotlinJarFile(folder))
- .addProgramFiles(getJavaJarFile(folder))
- .addProgramFiles(ToolHelper.getKotlinReflectJar())
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+ .addProgramFiles(getJavaJarFile(FOLDER))
+ .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinc))
.addKeepMainRule(mainClassName)
.addKeepKotlinMetadata()
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
diff --git a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
index e262f66..9cd2614 100644
--- a/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/metadata/MetadataVersionNumberBumpTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.kotlin.metadata;
+import static com.android.tools.r8.ToolHelper.getKotlinC_1_3_72;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.fail;
import static org.objectweb.asm.Opcodes.ASM7;
@@ -43,7 +44,7 @@
}
public MetadataVersionNumberBumpTest(TestParameters parameters) {
- super(KotlinTargetVersion.JAVA_8);
+ super(KotlinTargetVersion.JAVA_8, getKotlinC_1_3_72());
this.parameters = parameters;
}
@@ -86,7 +87,7 @@
private void rewriteMetadataVersion(Consumer<byte[]> rewrittenBytesConsumer, int[] newVersion)
throws IOException {
ZipUtils.iter(
- ToolHelper.getKotlinStdlibJar().toString(),
+ ToolHelper.getKotlinStdlibJar(kotlinc).toString(),
((entry, input) -> {
if (!entry.getName().endsWith(".class")) {
return;
diff --git a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
index a2bb5df..53b9d9b 100644
--- a/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/reflection/KotlinReflectTest.java
@@ -4,12 +4,13 @@
package com.android.tools.r8.kotlin.reflection;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
-import com.android.tools.r8.TestBase;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -17,60 +18,50 @@
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
import java.io.File;
-import java.nio.file.Path;
import java.nio.file.Paths;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class KotlinReflectTest extends TestBase {
+public class KotlinReflectTest extends KotlinTestBase {
private final TestParameters parameters;
private final KotlinTargetVersion targetVersion;
private static final String EXPECTED_OUTPUT = "Hello World!";
private static final String PKG = KotlinReflectTest.class.getPackage().getName();
- private static Map<KotlinTargetVersion, Path> compiledJars = new HashMap<>();
+ private static final KotlinCompileMemoizer compiledJars =
+ getCompileMemoizer(
+ Paths.get(
+ ToolHelper.TESTS_DIR,
+ "java",
+ DescriptorUtils.getBinaryNameFromJavaType(PKG),
+ "SimpleReflect" + FileUtils.KT_EXTENSION));
- @Parameters(name = "{0}, target: {1}")
+ @Parameters(name = "{0}, target: {1}, kotlinc: {2}")
public static List<Object[]> data() {
return buildParameters(
- getTestParameters().withAllRuntimesAndApiLevels().build(), KotlinTargetVersion.values());
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
- public KotlinReflectTest(TestParameters parameters, KotlinTargetVersion targetVersion) {
+ public KotlinReflectTest(
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
this.targetVersion = targetVersion;
}
- @BeforeClass
- public static void createLibJar() throws Exception {
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- compiledJars.put(
- targetVersion,
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(
- Paths.get(
- ToolHelper.TESTS_DIR,
- "java",
- DescriptorUtils.getBinaryNameFromJavaType(PKG),
- "SimpleReflect" + FileUtils.KT_EXTENSION))
- .compile());
- }
- }
-
@Test
public void testCf() throws Exception {
assumeTrue(parameters.isCfRuntime());
testForJvm()
- .addProgramFiles(compiledJars.get(targetVersion))
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(ToolHelper.getKotlinReflectJar())
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinc))
.run(parameters.getRuntime(), PKG + ".SimpleReflectKt")
.assertSuccessWithOutputLines(EXPECTED_OUTPUT);
}
@@ -80,9 +71,9 @@
assumeTrue(parameters.isDexRuntime());
final File output = temp.newFile("output.zip");
testForD8(parameters.getBackend())
- .addProgramFiles(compiledJars.get(targetVersion))
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(ToolHelper.getKotlinReflectJar())
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinc))
.setProgramConsumer(new ArchiveConsumer(output.toPath(), true))
.setMinApi(parameters.getApiLevel())
.addOptionsModification(
@@ -98,9 +89,9 @@
public void testR8() throws Exception {
final File foo = temp.newFile("foo");
testForR8(parameters.getBackend())
- .addProgramFiles(compiledJars.get(targetVersion))
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(ToolHelper.getKotlinReflectJar())
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(ToolHelper.getKotlinReflectJar(kotlinc))
.setMinApi(parameters.getApiLevel())
.addKeepAllClassesRule()
.addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
diff --git a/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java b/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java
index 5731086..6b70ca2 100644
--- a/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/sealed/SealedClassTest.java
@@ -5,22 +5,21 @@
package com.android.tools.r8.kotlin.sealed;
import static com.android.tools.r8.DiagnosticsMatcher.diagnosticMessage;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static org.hamcrest.CoreMatchers.containsString;
import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestRuntime;
-import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.Collection;
import java.util.List;
import java.util.concurrent.ExecutionException;
-import java.util.function.BiFunction;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -37,30 +36,33 @@
@Parameters(name = "{0}")
public static List<Object[]> data() {
return buildParameters(
- getTestParameters().withAllRuntimesAndApiLevels().build(), KotlinTargetVersion.values());
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
- public SealedClassTest(TestParameters parameters, KotlinTargetVersion targetVersion) {
- super(targetVersion);
+ public SealedClassTest(
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static BiFunction<TestRuntime, KotlinTargetVersion, Path> compilationResults =
- memoizeBiFunction(SealedClassTest::compileKotlinCode);
+ private static final KotlinCompileMemoizer compilationResults =
+ getCompileMemoizer(getKotlinSources());
- private static Path compileKotlinCode(TestRuntime runtime, KotlinTargetVersion targetVersion)
- throws IOException {
- CfRuntime cfRuntime = runtime.isCf() ? runtime.asCf() : TestRuntime.getCheckedInJdk9();
- return kotlinc(cfRuntime, getStaticTemp(), KOTLINC, targetVersion)
- .addSourceFiles(getFilesInTestFolderRelativeToClass(SealedClassTest.class, "kt", ".kt"))
- .compile();
+ private static Collection<Path> getKotlinSources() {
+ try {
+ return getFilesInTestFolderRelativeToClass(SealedClassTest.class, "kt", ".kt");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
@Test
public void testRuntime() throws ExecutionException, CompilationFailedException, IOException {
testForRuntime(parameters)
- .addProgramFiles(compilationResults.apply(parameters.getRuntime(), targetVersion))
- .addRunClasspathFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar()))
+ .addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
+ .addRunClasspathFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar(kotlinc)))
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines(EXPECTED);
}
@@ -68,8 +70,8 @@
@Test
public void testR8() throws ExecutionException, CompilationFailedException, IOException {
testForR8(parameters.getBackend())
- .addProgramFiles(compilationResults.apply(parameters.getRuntime(), targetVersion))
- .addProgramFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar()))
+ .addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
+ .addProgramFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar(kotlinc)))
.setMinApi(parameters.getApiLevel())
.allowAccessModification()
.allowDiagnosticWarningMessages(parameters.isCfRuntime())
diff --git a/src/test/java/com/android/tools/r8/naming/AbstractR8KotlinNamingTestBase.java b/src/test/java/com/android/tools/r8/naming/AbstractR8KotlinNamingTestBase.java
index 9f2d940..ddc2da6 100644
--- a/src/test/java/com/android/tools/r8/naming/AbstractR8KotlinNamingTestBase.java
+++ b/src/test/java/com/android/tools/r8/naming/AbstractR8KotlinNamingTestBase.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.MatcherAssert.assertThat;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.kotlin.AbstractR8KotlinTestBase;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -21,9 +22,10 @@
AbstractR8KotlinNamingTestBase(
KotlinTargetVersion kotlinTargetVersion,
+ KotlinCompiler kotlinc,
boolean allowAccessModification,
boolean minification) {
- super(kotlinTargetVersion, allowAccessModification);
+ super(kotlinTargetVersion, kotlinc, allowAccessModification);
this.minification = minification;
}
diff --git a/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java b/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
index 73d9085..837459c 100644
--- a/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/naming/EnumMinificationKotlinTest.java
@@ -3,11 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -31,26 +33,34 @@
private final TestParameters parameters;
private final boolean minify;
- @Parameterized.Parameters(name = "{0} target: {1} minify: {2}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}, minify: {3}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
KotlinTargetVersion.values(),
+ getKotlinCompilers(),
BooleanUtils.values());
}
public EnumMinificationKotlinTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, boolean minify) {
- super(targetVersion);
+ TestParameters parameters,
+ KotlinTargetVersion targetVersion,
+ KotlinCompiler kotlinc,
+ boolean minify) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
this.minify = minify;
}
+ private static final KotlinCompileMemoizer compiledJars =
+ getCompileMemoizer(getKotlinFilesInResource(FOLDER), FOLDER)
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect());
+
@Test
public void b121221542() throws Exception {
CodeInspector inspector =
testForR8(parameters.getBackend())
- .addProgramFiles(getKotlinJarFile(FOLDER))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
.addProgramFiles(getJavaJarFile(FOLDER))
.addKeepMainRule(MAIN_CLASS_NAME)
.addKeepClassRulesWithAllowObfuscation(ENUM_CLASS_NAME)
diff --git a/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java b/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
index 93a0639..70a9cb2 100644
--- a/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
+++ b/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
@@ -3,12 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.naming;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestCompileResult;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -38,17 +40,27 @@
public class KotlinIntrinsicsIdentifierTest extends AbstractR8KotlinNamingTestBase {
private static final String FOLDER = "intrinsics_identifiers";
- @Parameters(name = "target: {0}, allowAccessModification: {1}, minification: {2}")
+ @Parameters(name = "target: {0}, kotlinc: {1}, allowAccessModification: {2}, minification: {3}")
public static Collection<Object[]> data() {
return buildParameters(
- KotlinTargetVersion.values(), BooleanUtils.values(), BooleanUtils.values());
+ KotlinTargetVersion.values(),
+ getKotlinCompilers(),
+ BooleanUtils.values(),
+ BooleanUtils.values());
}
public KotlinIntrinsicsIdentifierTest(
- KotlinTargetVersion targetVersion, boolean allowAccessModification, boolean minification) {
- super(targetVersion, allowAccessModification, minification);
+ KotlinTargetVersion targetVersion,
+ KotlinCompiler kotlinc,
+ boolean allowAccessModification,
+ boolean minification) {
+ super(targetVersion, kotlinc, allowAccessModification, minification);
}
+ private static final KotlinCompileMemoizer compiledJars =
+ getCompileMemoizer(getKotlinFilesInResource(FOLDER), FOLDER)
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect());
+
@Test
public void test_example1() throws Exception {
TestKotlinClass ex1 = new TestKotlinClass("intrinsics_identifiers.Example1Kt");
@@ -71,9 +83,9 @@
public void test_example3() throws Exception {
TestKotlinClass ex3 = new TestKotlinClass("intrinsics_identifiers.Example3Kt");
String mainClassName = ex3.getClassName();
- TestCompileResult result =
+ TestCompileResult<?, ?> result =
testForR8(Backend.DEX)
- .addProgramFiles(getKotlinJarFile(FOLDER))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
.addProgramFiles(getJavaJarFile(FOLDER))
.addKeepMainRule(mainClassName)
.allowDiagnosticWarningMessages()
@@ -124,9 +136,9 @@
String targetFieldName,
String targetMethodName) throws Exception {
String mainClassName = testMain.getClassName();
- SingleTestRunResult result =
+ SingleTestRunResult<?> result =
testForR8(Backend.DEX)
- .addProgramFiles(getKotlinJarFile(FOLDER))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
.addProgramFiles(getJavaJarFile(FOLDER))
.enableProguardTestOptions()
.addKeepMainRule(mainClassName)
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java b/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
index a64903b..668206c 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
@@ -16,6 +16,7 @@
import com.google.common.base.Equivalence;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -487,6 +488,53 @@
}
}
+ // Equivalence comparing stack traces without taking the line number for a specific stack trace
+ // line into account.
+ public static class EquivalenceWithoutSpecificLineNumber extends StackTraceEquivalence {
+
+ private StackTraceLine lineToIgnoreLineNumberFor;
+
+ private EquivalenceWithoutSpecificLineNumber(StackTraceLine lineToIgnoreLineNumberFor) {
+ this.lineToIgnoreLineNumberFor = lineToIgnoreLineNumberFor;
+ }
+
+ public static EquivalenceWithoutSpecificLineNumber create(
+ StackTraceLine lineToIgnoreLineNumberFor) {
+ return new EquivalenceWithoutSpecificLineNumber(lineToIgnoreLineNumberFor);
+ }
+
+ public class LineEquivalence extends Equivalence<StackTraceLine> {
+
+ private LineEquivalence() {}
+
+ @Override
+ protected boolean doEquivalent(StackTraceLine a, StackTraceLine b) {
+ if (!a.className.equals(b.className)
+ || !a.methodName.equals(b.methodName)
+ || !a.fileName.equals(b.fileName)) {
+ return false;
+ }
+ if (a.lineNumber == b.lineNumber) {
+ return true;
+ }
+ return a.className.equals(lineToIgnoreLineNumberFor.className)
+ && a.methodName.equals(lineToIgnoreLineNumberFor.methodName)
+ && a.fileName.equals(lineToIgnoreLineNumberFor.fileName);
+ }
+
+ @Override
+ protected int doHash(StackTraceLine stackTraceLine) {
+ return Objects.hash(
+ stackTraceLine.className, stackTraceLine.methodName, stackTraceLine.fileName);
+ }
+ }
+
+ @Override
+ public Equivalence<StackTraceLine> getLineEquivalence() {
+ return new LineEquivalence();
+ }
+ }
+
public static class StackTraceMatcherBase extends TypeSafeMatcher<StackTrace> {
private final StackTrace expected;
private final StackTraceEquivalence equivalence;
@@ -568,4 +616,19 @@
public static Matcher<StackTrace> isSameExceptForFileNameAndLineNumber(StackTrace stackTrace) {
return new StackTraceIgnoreFileNameAndLineNumberMatcher(stackTrace);
}
+
+ public static class StackTraceIgnoreSpecificLineNumberMatcher extends StackTraceMatcherBase {
+ private StackTraceIgnoreSpecificLineNumberMatcher(
+ StackTrace expected, StackTraceLine lineToIgnoreLineNumberFor) {
+ super(
+ expected,
+ EquivalenceWithoutSpecificLineNumber.create(lineToIgnoreLineNumberFor),
+ "(ignoring file name and line number)");
+ }
+ }
+
+ public static Matcher<StackTrace> isSameExceptForSpecificLineNumber(
+ StackTrace stackTrace, StackTraceLine lineToIgnoreLineNumberFor) {
+ return new StackTraceIgnoreSpecificLineNumberMatcher(stackTrace, lineToIgnoreLineNumberFor);
+ }
}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageProtectedInSeparatePackageTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageProtectedInSeparatePackageTest.java
index a455d0e..a5e0ea3 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageProtectedInSeparatePackageTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageProtectedInSeparatePackageTest.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.repackage;
+import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverClassInline;
@@ -46,15 +47,14 @@
.compile()
.inspect(
inspector -> {
- // TODO(b/173584786): We should not repackage Sub when generating CF.
- assertThat(Sub.class, isRepackaged(inspector));
+ if (parameters.isCfRuntime()) {
+ assertThat(Sub.class, not(isRepackaged(inspector)));
+ } else {
+ assertThat(Sub.class, isRepackaged(inspector));
+ }
})
- .run(parameters.getRuntime(), Main.class);
- if (parameters.isCfRuntime()) {
- runResult.assertFailureWithErrorThatThrows(VerifyError.class);
- } else {
- runResult.assertSuccessWithOutputLines(EXPECTED);
- }
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
}
public static class Base {
diff --git a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java
index 0beee59..274b990 100644
--- a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java
+++ b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionInSameFileRetraceTests.java
@@ -4,8 +4,8 @@
package com.android.tools.r8.retrace;
import static com.android.tools.r8.Collectors.toSingle;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.containsLinePositions;
import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineFrame;
import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineStack;
@@ -16,11 +16,9 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.TestBase;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime;
-import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.naming.retrace.StackTrace;
@@ -30,15 +28,16 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
import java.util.concurrent.ExecutionException;
-import java.util.function.Function;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class KotlinInlineFunctionInSameFileRetraceTests extends TestBase {
+public class KotlinInlineFunctionInSameFileRetraceTests extends KotlinTestBase {
private static final String FILENAME_INLINE = "InlineFunctionsInSameFile.kt";
private static final String MAIN = "retrace.InlineFunctionsInSameFileKt";
@@ -46,30 +45,37 @@
private final TestParameters parameters;
@Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimesAndApiLevels().build();
+ public static List<Object[]> data() {
+ // TODO(b/141817471): Extend with compilation modes.
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
- public KotlinInlineFunctionInSameFileRetraceTests(TestParameters parameters) {
+ public KotlinInlineFunctionInSameFileRetraceTests(
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Function<TestRuntime, Path> compilationResults =
- memoizeFunction(KotlinInlineFunctionInSameFileRetraceTests::compileKotlinCode);
+ private static final KotlinCompileMemoizer compilationResults =
+ getCompileMemoizer(getKotlinSources());
- private static Path compileKotlinCode(TestRuntime runtime) throws IOException {
- CfRuntime cfRuntime = runtime.isCf() ? runtime.asCf() : TestRuntime.getCheckedInJdk9();
- return kotlinc(cfRuntime, getStaticTemp(), KOTLINC, KotlinTargetVersion.JAVA_8)
- .addSourceFiles(
- getFilesInTestFolderRelativeToClass(KotlinInlineFunctionRetraceTest.class, "kt", ".kt"))
- .compile();
+ private static Collection<Path> getKotlinSources() {
+ try {
+ return getFilesInTestFolderRelativeToClass(
+ KotlinInlineFunctionRetraceTest.class, "kt", ".kt");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
@Test
public void testRuntime() throws ExecutionException, CompilationFailedException, IOException {
testForRuntime(parameters)
- .addProgramFiles(compilationResults.apply(parameters.getRuntime()))
- .addRunClasspathFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar()))
+ .addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
+ .addRunClasspathFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar(kotlinc)))
.run(parameters.getRuntime(), MAIN)
.assertFailureWithErrorThatMatches(containsString("foo"))
.assertFailureWithErrorThatMatches(
@@ -80,11 +86,11 @@
@Test
public void testRetraceKotlinInlineStaticFunction()
throws ExecutionException, CompilationFailedException, IOException {
- Path kotlinSources = compilationResults.apply(parameters.getRuntime());
+ Path kotlinSources = compilationResults.getForConfiguration(kotlinc, targetVersion);
CodeInspector kotlinInspector = new CodeInspector(kotlinSources);
testForR8(parameters.getBackend())
- .addProgramFiles(compilationResults.apply(parameters.getRuntime()))
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
.addKeepAttributes("SourceFile", "LineNumberTable")
.setMode(CompilationMode.RELEASE)
.addKeepMainRule(MAIN)
diff --git a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionRetraceTest.java b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionRetraceTest.java
index 3b0538d..53d2a7c 100644
--- a/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionRetraceTest.java
+++ b/src/test/java/com/android/tools/r8/retrace/KotlinInlineFunctionRetraceTest.java
@@ -5,8 +5,8 @@
package com.android.tools.r8.retrace;
import static com.android.tools.r8.Collectors.toSingle;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
import static com.android.tools.r8.ToolHelper.getFilesInTestFolderRelativeToClass;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.containsLinePositions;
import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineFrame;
import static com.android.tools.r8.utils.codeinspector.Matchers.isInlineStack;
@@ -17,11 +17,9 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.TestBase;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
+import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.TestRuntime;
-import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
import com.android.tools.r8.naming.retrace.StackTrace;
@@ -32,15 +30,16 @@
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.Collection;
+import java.util.List;
import java.util.concurrent.ExecutionException;
-import java.util.function.Function;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class KotlinInlineFunctionRetraceTest extends TestBase {
+public class KotlinInlineFunctionRetraceTest extends KotlinTestBase {
private final TestParameters parameters;
// TODO(b/151132660): Fix filename
@@ -48,24 +47,30 @@
private static final String FILENAME_INLINE_INSTANCE = "InlineFunction.kt";
@Parameters(name = "{0}")
- public static TestParametersCollection data() {
+ public static List<Object[]> data() {
// TODO(b/141817471): Extend with compilation modes.
- return getTestParameters().withAllRuntimesAndApiLevels().build();
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ KotlinTargetVersion.values(),
+ getKotlinCompilers());
}
- public KotlinInlineFunctionRetraceTest(TestParameters parameters) {
+ public KotlinInlineFunctionRetraceTest(
+ TestParameters parameters, KotlinTargetVersion targetVersion, KotlinCompiler kotlinc) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
}
- private static Function<TestRuntime, Path> compilationResults =
- memoizeFunction(KotlinInlineFunctionRetraceTest::compileKotlinCode);
+ private static final KotlinCompileMemoizer compilationResults =
+ getCompileMemoizer(getKotlinSources());
- private static Path compileKotlinCode(TestRuntime runtime) throws IOException {
- CfRuntime cfRuntime = runtime.isCf() ? runtime.asCf() : TestRuntime.getCheckedInJdk9();
- return kotlinc(cfRuntime, getStaticTemp(), KOTLINC, KotlinTargetVersion.JAVA_8)
- .addSourceFiles(
- getFilesInTestFolderRelativeToClass(KotlinInlineFunctionRetraceTest.class, "kt", ".kt"))
- .compile();
+ private static Collection<Path> getKotlinSources() {
+ try {
+ return getFilesInTestFolderRelativeToClass(
+ KotlinInlineFunctionRetraceTest.class, "kt", ".kt");
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
}
private FoundMethodSubject inlineExceptionStatic(CodeInspector kotlinInspector) {
@@ -85,8 +90,8 @@
@Test
public void testRuntime() throws ExecutionException, CompilationFailedException, IOException {
testForRuntime(parameters)
- .addProgramFiles(compilationResults.apply(parameters.getRuntime()))
- .addRunClasspathFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar()))
+ .addProgramFiles(compilationResults.getForConfiguration(kotlinc, targetVersion))
+ .addRunClasspathFiles(buildOnDexRuntime(parameters, ToolHelper.getKotlinStdlibJar(kotlinc)))
.run(parameters.getRuntime(), "retrace.MainKt")
.assertFailureWithErrorThatMatches(containsString("inlineExceptionStatic"))
.assertFailureWithErrorThatMatches(containsString("at retrace.MainKt.main(Main.kt:15)"));
@@ -97,10 +102,10 @@
throws ExecutionException, CompilationFailedException, IOException {
String main = "retrace.MainKt";
String mainFileName = "Main.kt";
- Path kotlinSources = compilationResults.apply(parameters.getRuntime());
+ Path kotlinSources = compilationResults.getForConfiguration(kotlinc, targetVersion);
CodeInspector kotlinInspector = new CodeInspector(kotlinSources);
testForR8(parameters.getBackend())
- .addProgramFiles(kotlinSources, ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(kotlinSources, ToolHelper.getKotlinStdlibJar(kotlinc))
.addKeepAttributes("SourceFile", "LineNumberTable")
.allowDiagnosticWarningMessages()
.setMode(CompilationMode.RELEASE)
@@ -127,10 +132,10 @@
throws ExecutionException, CompilationFailedException, IOException {
String main = "retrace.MainInstanceKt";
String mainFileName = "MainInstance.kt";
- Path kotlinSources = compilationResults.apply(parameters.getRuntime());
+ Path kotlinSources = compilationResults.getForConfiguration(kotlinc, targetVersion);
CodeInspector kotlinInspector = new CodeInspector(kotlinSources);
testForR8(parameters.getBackend())
- .addProgramFiles(kotlinSources, ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(kotlinSources, ToolHelper.getKotlinStdlibJar(kotlinc))
.addKeepAttributes("SourceFile", "LineNumberTable")
.allowDiagnosticWarningMessages()
.setMode(CompilationMode.RELEASE)
@@ -160,10 +165,10 @@
throws ExecutionException, CompilationFailedException, IOException {
String main = "retrace.MainNestedKt";
String mainFileName = "MainNested.kt";
- Path kotlinSources = compilationResults.apply(parameters.getRuntime());
+ Path kotlinSources = compilationResults.getForConfiguration(kotlinc, targetVersion);
CodeInspector kotlinInspector = new CodeInspector(kotlinSources);
testForR8(parameters.getBackend())
- .addProgramFiles(kotlinSources, ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(kotlinSources, ToolHelper.getKotlinStdlibJar(kotlinc))
.addKeepAttributes("SourceFile", "LineNumberTable")
.allowDiagnosticWarningMessages()
.setMode(CompilationMode.RELEASE)
@@ -192,10 +197,10 @@
throws ExecutionException, CompilationFailedException, IOException {
String main = "retrace.MainNestedFirstLineKt";
String mainFileName = "MainNestedFirstLine.kt";
- Path kotlinSources = compilationResults.apply(parameters.getRuntime());
+ Path kotlinSources = compilationResults.getForConfiguration(kotlinc, targetVersion);
CodeInspector kotlinInspector = new CodeInspector(kotlinSources);
testForR8(parameters.getBackend())
- .addProgramFiles(kotlinSources, ToolHelper.getKotlinStdlibJar())
+ .addProgramFiles(kotlinSources, ToolHelper.getKotlinStdlibJar(kotlinc))
.addKeepAttributes("SourceFile", "LineNumberTable")
.allowDiagnosticWarningMessages()
.setMode(CompilationMode.RELEASE)
diff --git a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
index 0be3ece..64ea164 100644
--- a/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
+++ b/src/test/java/com/android/tools/r8/rewrite/assertions/AssertionConfigurationKotlinTest.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.rewrite.assertions;
-import static com.android.tools.r8.KotlinCompilerTool.KOTLINC;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.not;
@@ -15,6 +15,7 @@
import com.android.tools.r8.AssertionsConfiguration;
import com.android.tools.r8.D8TestBuilder;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.TestParameters;
@@ -28,14 +29,11 @@
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
+import java.io.IOException;
import java.nio.file.Path;
import java.util.Collection;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
-import java.util.Objects;
import org.junit.Assume;
-import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -47,51 +45,31 @@
@RunWith(Parameterized.class)
public class AssertionConfigurationKotlinTest extends KotlinTestBase implements Opcodes {
- private static class KotlinCompilationKey {
- KotlinTargetVersion targetVersion;
- boolean useJvmAssertions;
-
- private KotlinCompilationKey(KotlinTargetVersion targetVersion, boolean useJvmAssertions) {
- this.targetVersion = targetVersion;
- this.useJvmAssertions = useJvmAssertions;
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(targetVersion, useJvmAssertions);
- }
-
- @Override
- public boolean equals(Object other) {
- if (other == null) {
- return false;
- }
- if (getClass() != other.getClass()) {
- return false;
- }
- KotlinCompilationKey kotlinCompilationKey = (KotlinCompilationKey) other;
- return targetVersion == kotlinCompilationKey.targetVersion
- && useJvmAssertions == kotlinCompilationKey.useJvmAssertions;
- }
- }
-
private static final Package pkg = AssertionConfigurationKotlinTest.class.getPackage();
private static final String kotlintestclasesPackage = pkg.getName() + ".kotlintestclasses";
private static final String testClassKt = kotlintestclasesPackage + ".TestClassKt";
private static final String class1 = kotlintestclasesPackage + ".Class1";
private static final String class2 = kotlintestclasesPackage + ".Class2";
- private static final Map<KotlinCompilationKey, Path> kotlinClasses = new HashMap<>();
+ private static final KotlinCompileMemoizer kotlinWithJvmAssertions =
+ getCompileMemoizer(getKotlinFilesForPackage())
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.setUseJvmAssertions(true));
+ private static final KotlinCompileMemoizer kotlinWithoutJvmAssertions =
+ getCompileMemoizer(getKotlinFilesForPackage())
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.setUseJvmAssertions(false));
+
private final TestParameters parameters;
private final boolean kotlinStdlibAsLibrary;
private final boolean useJvmAssertions;
- private final KotlinCompilationKey kotlinCompilationKey;
+ private final KotlinCompileMemoizer compiledForAssertions;
- @Parameterized.Parameters(name = "{0}, {1}, kotlin-stdlib as library: {2}, -Xassertions=jvm: {3}")
+ @Parameterized.Parameters(
+ name = "{0}, target: {1}, kotlinc: {2}, kotlin-stdlib as library: {3}, -Xassertions=jvm: {4}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
KotlinTargetVersion.values(),
+ getKotlinCompilers(),
BooleanUtils.values(),
BooleanUtils.values());
}
@@ -99,31 +77,27 @@
public AssertionConfigurationKotlinTest(
TestParameters parameters,
KotlinTargetVersion targetVersion,
+ KotlinCompiler kotlinc,
boolean kotlinStdlibAsClasspath,
boolean useJvmAssertions) {
- super(targetVersion);
+ super(targetVersion, kotlinc);
this.parameters = parameters;
this.kotlinStdlibAsLibrary = kotlinStdlibAsClasspath;
this.useJvmAssertions = useJvmAssertions;
- this.kotlinCompilationKey = new KotlinCompilationKey(targetVersion, useJvmAssertions);
+ this.compiledForAssertions =
+ useJvmAssertions ? kotlinWithJvmAssertions : kotlinWithoutJvmAssertions;
}
- @BeforeClass
- public static void compileKotlin() throws Exception {
- for (KotlinTargetVersion targetVersion : KotlinTargetVersion.values()) {
- for (boolean useJvmAssertions : BooleanUtils.values()) {
- Path ktClasses =
- kotlinc(KOTLINC, targetVersion)
- .addSourceFiles(getKotlinFilesInTestPackage(pkg))
- .setUseJvmAssertions(useJvmAssertions)
- .compile();
- kotlinClasses.put(new KotlinCompilationKey(targetVersion, useJvmAssertions), ktClasses);
- }
+ private static List<Path> getKotlinFilesForPackage() {
+ try {
+ return getKotlinFilesInTestPackage(pkg);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
}
}
private Path kotlinStdlibLibraryForRuntime() throws Exception {
- Path kotlinStdlibCf = ToolHelper.getKotlinStdlibJar();
+ Path kotlinStdlibCf = ToolHelper.getKotlinStdlibJar(kotlinc);
if (parameters.getRuntime().isCf()) {
return kotlinStdlibCf;
}
@@ -144,8 +118,8 @@
throws Exception {
if (kotlinStdlibAsLibrary) {
testForD8()
- .addClasspathFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(kotlinClasses.get(kotlinCompilationKey))
+ .addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
.setMinApi(parameters.getApiLevel())
.apply(builderConsumer)
.addRunClasspathFiles(kotlinStdlibLibraryForRuntime())
@@ -156,8 +130,8 @@
.assertSuccessWithOutputLines(outputLines);
} else {
testForD8()
- .addProgramFiles(ToolHelper.getKotlinStdlibJar())
- .addProgramFiles(kotlinClasses.get(kotlinCompilationKey))
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc))
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
.setMinApi(parameters.getApiLevel())
.apply(builderConsumer)
.run(
@@ -187,11 +161,11 @@
.applyIf(
kotlinStdlibAsLibrary,
b -> {
- b.addClasspathFiles(ToolHelper.getKotlinStdlibJar());
+ b.addClasspathFiles(ToolHelper.getKotlinStdlibJar(kotlinc));
b.addRunClasspathFiles(kotlinStdlibLibraryForRuntime());
},
- b -> b.addProgramFiles(ToolHelper.getKotlinStdlibJar()))
- .addProgramFiles(kotlinClasses.get(kotlinCompilationKey))
+ b -> b.addProgramFiles(ToolHelper.getKotlinStdlibJar(kotlinc)))
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
.addKeepMainRule(testClassKt)
.addKeepClassAndMembersRules(class1, class2)
.setMinApi(parameters.getApiLevel())
@@ -476,7 +450,7 @@
public void testAssertionsForCfEnableWithStackMap() throws Exception {
Assume.assumeTrue(parameters.isCfRuntime());
Assume.assumeTrue(useJvmAssertions);
- Assume.assumeTrue(kotlinCompilationKey.targetVersion == KotlinTargetVersion.JAVA_8);
+ Assume.assumeTrue(targetVersion == KotlinTargetVersion.JAVA_8);
// Compile time enabling or disabling assertions means the -ea flag has no effect.
runR8Test(
builder -> {
@@ -554,7 +528,7 @@
Assume.assumeTrue(parameters.isDexRuntime());
testForD8()
.addProgramClassFileData(dumpModifiedKotlinAssertions())
- .addProgramFiles(kotlinClasses.get(kotlinCompilationKey))
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
.setMinApi(parameters.getApiLevel())
.addAssertionsConfiguration(AssertionsConfiguration.Builder::passthroughAllAssertions)
.run(
@@ -563,7 +537,7 @@
.assertSuccessWithOutputLines(noAllAssertionsExpectedLines());
testForD8()
.addProgramClassFileData(dumpModifiedKotlinAssertions())
- .addProgramFiles(kotlinClasses.get(kotlinCompilationKey))
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
.setMinApi(parameters.getApiLevel())
.addAssertionsConfiguration(AssertionsConfiguration.Builder::enableAllAssertions)
.run(
@@ -572,7 +546,7 @@
.assertSuccessWithOutputLines(allAssertionsExpectedLines());
testForD8()
.addProgramClassFileData(dumpModifiedKotlinAssertions())
- .addProgramFiles(kotlinClasses.get(kotlinCompilationKey))
+ .addProgramFiles(compiledForAssertions.getForConfiguration(kotlinc, targetVersion))
.setMinApi(parameters.getApiLevel())
.addAssertionsConfiguration(AssertionsConfiguration.Builder::disableAllAssertions)
.run(
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/ReflectiveAnnotationUseTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/ReflectiveAnnotationUseTest.java
index c975c82..9c358e8 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/ReflectiveAnnotationUseTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/ReflectiveAnnotationUseTest.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking.annotations;
+import static com.android.tools.r8.ToolHelper.getKotlinCompilers;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndNotRenamed;
import static org.hamcrest.CoreMatchers.containsString;
@@ -12,6 +13,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
+import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
import com.android.tools.r8.KotlinTestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper.KotlinTargetVersion;
@@ -60,28 +62,37 @@
private final TestParameters parameters;
private final boolean minify;
- @Parameterized.Parameters(name = "{0} target: {1} minify: {2}")
+ @Parameterized.Parameters(name = "{0}, target: {1}, kotlinc: {2}, minify: {3}")
public static Collection<Object[]> data() {
return buildParameters(
getTestParameters().withAllRuntimesAndApiLevels().build(),
KotlinTargetVersion.values(),
+ getKotlinCompilers(),
BooleanUtils.values());
}
public ReflectiveAnnotationUseTest(
- TestParameters parameters, KotlinTargetVersion targetVersion, boolean minify) {
- super(targetVersion);
+ TestParameters parameters,
+ KotlinTargetVersion targetVersion,
+ KotlinCompiler kotlinc,
+ boolean minify) {
+ super(targetVersion, kotlinc);
this.parameters = parameters;
this.minify = minify;
}
+ private static final KotlinCompileMemoizer compiledJars =
+ getCompileMemoizer(getKotlinFilesInResource(FOLDER), FOLDER)
+ .configure(kotlinCompilerTool -> kotlinCompilerTool.includeRuntime().noReflect());
+
@Test
public void b120951621_JVMOutput() throws Exception {
assumeTrue("Only run JVM reference on CF runtimes", parameters.isCfRuntime());
- AndroidApp app = AndroidApp.builder()
- .addProgramFile(getKotlinJarFile(FOLDER))
- .addProgramFile(getJavaJarFile(FOLDER))
- .build();
+ AndroidApp app =
+ AndroidApp.builder()
+ .addProgramFile(compiledJars.getForConfiguration(kotlinc, targetVersion))
+ .addProgramFile(getJavaJarFile(FOLDER))
+ .build();
String result = runOnJava(app, MAIN_CLASS_NAME);
assertEquals(JAVA_OUTPUT, result);
}
@@ -90,7 +101,7 @@
public void b120951621_keepAll() throws Exception {
CodeInspector inspector =
testForR8(parameters.getBackend())
- .addProgramFiles(getKotlinJarFile(FOLDER))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
.addProgramFiles(getJavaJarFile(FOLDER))
.addKeepMainRule(MAIN_CLASS_NAME)
.addKeepRules(KEEP_ANNOTATIONS)
@@ -126,7 +137,7 @@
public void b120951621_partiallyKeep() throws Exception {
CodeInspector inspector =
testForR8(parameters.getBackend())
- .addProgramFiles(getKotlinJarFile(FOLDER))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
.addProgramFiles(getJavaJarFile(FOLDER))
.addKeepMainRule(MAIN_CLASS_NAME)
.addKeepRules(KEEP_ANNOTATIONS)
@@ -166,7 +177,7 @@
public void b120951621_keepAnnotation() throws Exception {
CodeInspector inspector =
testForR8(parameters.getBackend())
- .addProgramFiles(getKotlinJarFile(FOLDER))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
.addProgramFiles(getJavaJarFile(FOLDER))
.addKeepMainRule(MAIN_CLASS_NAME)
.addKeepRules(KEEP_ANNOTATIONS)
@@ -202,7 +213,7 @@
public void b120951621_noKeep() throws Exception {
CodeInspector inspector =
testForR8(parameters.getBackend())
- .addProgramFiles(getKotlinJarFile(FOLDER))
+ .addProgramFiles(compiledJars.getForConfiguration(kotlinc, targetVersion))
.addProgramFiles(getJavaJarFile(FOLDER))
.addKeepMainRule(MAIN_CLASS_NAME)
.allowDiagnosticWarningMessages()
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java
index 4f65b48..1c7f6ac 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationTest.java
@@ -157,7 +157,8 @@
.addKeepMainRule(MAIN)
.addKeepRules(config.getKeepRules())
.addOptionsModification(
- options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ options ->
+ options.horizontalClassMergerOptions().enableIf(enableHorizontalClassMerging))
.enableInliningAnnotations()
.noMinification()
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesCommandTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesCommandTest.java
index cbded10..25a8684 100644
--- a/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesCommandTest.java
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesCommandTest.java
@@ -3,6 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.tracereferences;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.fail;
@@ -524,12 +526,95 @@
Origin.unknown(),
diagnosticsChecker)
.build());
-
assertEquals(0, diagnosticsChecker.errors.size());
assertEquals(1, diagnosticsChecker.warnings.size());
assertEquals(0, diagnosticsChecker.infos.size());
}
+ @Test
+ public void testMissingReference_errorToWarningStdErr() throws Throwable {
+ Path dir = temp.newFolder().toPath();
+ Path targetJar =
+ zipWithTestClasses(dir.resolve("target.jar"), ImmutableList.of(OtherTarget.class));
+ Path sourceJar = zipWithTestClasses(dir.resolve("source.jar"), ImmutableList.of(Source.class));
+ PrintStream originalErr = System.err;
+ PrintStream originalOut = System.out;
+ ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
+ ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
+ try {
+ System.setErr(new PrintStream(baosErr));
+ System.setOut(new PrintStream(baosOut));
+ TraceReferences.run(
+ TraceReferencesCommand.parse(
+ new String[] {
+ "--check",
+ "--lib",
+ ToolHelper.getAndroidJar(AndroidApiLevel.P).toString(),
+ "--target",
+ targetJar.toString(),
+ "--source",
+ sourceJar.toString(),
+ "--map-diagnostics:MissingDefinitionsDiagnostic",
+ "error",
+ "warning"
+ },
+ Origin.unknown())
+ .build());
+ } finally {
+ System.setErr(originalErr);
+ System.setOut(originalOut);
+ }
+
+ assertThat(
+ baosErr.toString(Charsets.UTF_8.name()),
+ containsString(
+ "Warning: Tracereferences found 1 classe(s), 1 field(s) and 1 method(s) without"
+ + " definition"));
+ assertEquals(0, baosOut.size());
+ }
+
+ @Test
+ public void testMissingReference_errorToInfoStdOut() throws Throwable {
+ Path dir = temp.newFolder().toPath();
+ Path targetJar =
+ zipWithTestClasses(dir.resolve("target.jar"), ImmutableList.of(OtherTarget.class));
+ Path sourceJar = zipWithTestClasses(dir.resolve("source.jar"), ImmutableList.of(Source.class));
+ PrintStream originalErr = System.err;
+ PrintStream originalOut = System.out;
+ ByteArrayOutputStream baosErr = new ByteArrayOutputStream();
+ ByteArrayOutputStream baosOut = new ByteArrayOutputStream();
+ try {
+ System.setErr(new PrintStream(baosErr));
+ System.setOut(new PrintStream(baosOut));
+ TraceReferences.run(
+ TraceReferencesCommand.parse(
+ new String[] {
+ "--check",
+ "--lib",
+ ToolHelper.getAndroidJar(AndroidApiLevel.P).toString(),
+ "--target",
+ targetJar.toString(),
+ "--source",
+ sourceJar.toString(),
+ "--map-diagnostics:MissingDefinitionsDiagnostic",
+ "error",
+ "info"
+ },
+ Origin.unknown())
+ .build());
+ } finally {
+ System.setErr(originalErr);
+ System.setOut(originalOut);
+ }
+
+ assertEquals(0, baosErr.size());
+ assertThat(
+ baosOut.toString(Charsets.UTF_8.name()),
+ containsString(
+ "Info: Tracereferences found 1 classe(s), 1 field(s) and 1 method(s) without"
+ + " definition"));
+ }
+
private void checkTargetPartlyMissing(DiagnosticsChecker diagnosticsChecker) {
Field field;
Method method;
diff --git a/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesDiagnosticTest.java b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesDiagnosticTest.java
index cad4538..418a282 100644
--- a/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesDiagnosticTest.java
+++ b/src/test/java/com/android/tools/r8/tracereferences/TraceReferencesDiagnosticTest.java
@@ -172,6 +172,8 @@
DiagnosticsChecker.checkErrorDiagnostics(
checker -> {
DiagnosticsChecker.checkContains(snippets, checker.errors);
+ DiagnosticsChecker.checkNotContains(
+ ImmutableList.of("Classe(s) without definition:"), checker.errors);
try {
assertEquals(1, checker.errors.size());
assertTrue(checker.errors.get(0) instanceof MissingDefinitionsDiagnostic);
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
index 28f419f..ffe8151 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
@@ -101,6 +101,16 @@
}
@Override
+ public boolean isImplementing(Class<?> clazz) {
+ throw new Unreachable("Cannot determine if an absent class is implementing a given interface");
+ }
+
+ @Override
+ public boolean isImplementing(String javaTypeName) {
+ throw new Unreachable("Cannot determine if an absent class is implementing a given interface");
+ }
+
+ @Override
public DexProgramClass getDexProgramClass() {
return null;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index ff544ab..a2d32eb 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -169,6 +169,10 @@
public abstract boolean isImplementing(ClassSubject subject);
+ public abstract boolean isImplementing(Class<?> clazz);
+
+ public abstract boolean isImplementing(String javaTypeName);
+
public String dumpMethods() {
StringBuilder dump = new StringBuilder();
forAllMethods(
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java
index ed4d158..654f3a1 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CodeMatchers.java
@@ -44,6 +44,37 @@
};
}
+ public static Matcher<MethodSubject> instantiatesClass(Class<?> clazz) {
+ return instantiatesClass(clazz.getTypeName());
+ }
+
+ public static Matcher<MethodSubject> instantiatesClass(String clazz) {
+ return new TypeSafeMatcher<MethodSubject>() {
+ @Override
+ protected boolean matchesSafely(MethodSubject subject) {
+ if (!subject.isPresent()) {
+ return false;
+ }
+ if (!subject.getMethod().hasCode()) {
+ return false;
+ }
+ return subject
+ .streamInstructions()
+ .anyMatch(instruction -> instruction.isNewInstance(clazz));
+ }
+
+ @Override
+ public void describeTo(Description description) {
+ description.appendText("instantiates class `" + clazz + "`");
+ }
+
+ @Override
+ public void describeMismatchSafely(final MethodSubject subject, Description description) {
+ description.appendText("method did not");
+ }
+ };
+ }
+
public static Matcher<MethodSubject> invokesMethod(MethodSubject targetSubject) {
if (!targetSubject.isPresent()) {
throw new IllegalArgumentException();
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/EnumUnboxingInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/EnumUnboxingInspector.java
index 8e5495e..2d41c1f 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/EnumUnboxingInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/EnumUnboxingInspector.java
@@ -8,21 +8,20 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.EnumValueInfoMapCollection;
+import com.android.tools.r8.ir.optimize.enums.EnumDataMap;
public class EnumUnboxingInspector {
private final DexItemFactory dexItemFactory;
- private final EnumValueInfoMapCollection unboxedEnums;
+ private final EnumDataMap unboxedEnums;
- public EnumUnboxingInspector(
- DexItemFactory dexItemFactory, EnumValueInfoMapCollection unboxedEnums) {
+ public EnumUnboxingInspector(DexItemFactory dexItemFactory, EnumDataMap unboxedEnums) {
this.dexItemFactory = dexItemFactory;
this.unboxedEnums = unboxedEnums;
}
public EnumUnboxingInspector assertUnboxed(Class<? extends Enum<?>> clazz) {
- assertTrue(unboxedEnums.containsEnum(toDexType(clazz, dexItemFactory)));
+ assertTrue(unboxedEnums.isUnboxedEnum(toDexType(clazz, dexItemFactory)));
return this;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index eafb952..a676666 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -311,6 +311,21 @@
}
@Override
+ public boolean isImplementing(Class<?> clazz) {
+ return isImplementing(clazz.getTypeName());
+ }
+
+ @Override
+ public boolean isImplementing(String javaTypeName) {
+ for (DexType itf : getDexProgramClass().interfaces) {
+ if (itf.toSourceString().equals(javaTypeName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
public boolean isAnnotation() {
return dexClass.accessFlags.isAnnotation();
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java
index 37dbe19..7cfc3fe 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/HorizontallyMergedClassesInspector.java
@@ -12,6 +12,8 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.horizontalclassmerging.HorizontallyMergedClasses;
+import com.android.tools.r8.utils.SetUtils;
+import com.google.common.collect.Sets;
import java.util.Set;
import java.util.function.BiConsumer;
@@ -30,10 +32,29 @@
horizontallyMergedClasses.forEachMergeGroup(consumer);
}
+ public Set<Set<DexType>> getMergeGroups() {
+ Set<Set<DexType>> mergeGroups = Sets.newLinkedHashSet();
+ forEachMergeGroup(
+ (sources, target) -> {
+ Set<DexType> mergeGroup = SetUtils.newIdentityHashSet(sources);
+ mergeGroup.add(target);
+ mergeGroups.add(mergeGroup);
+ });
+ return mergeGroups;
+ }
+
+ public Set<DexType> getSources() {
+ return horizontallyMergedClasses.getSources();
+ }
+
public DexType getTarget(DexType clazz) {
return horizontallyMergedClasses.getMergeTargetOrDefault(clazz);
}
+ public Set<DexType> getTargets() {
+ return horizontallyMergedClasses.getTargets();
+ }
+
public HorizontallyMergedClassesInspector assertMergedInto(Class<?> from, Class<?> target) {
assertEquals(
horizontallyMergedClasses.getMergeTargetOrDefault(toDexType(from, dexItemFactory)),
diff --git a/third_party/kotlin/kotlin-compiler-1.4.20.tar.gz.sha1 b/third_party/kotlin/kotlin-compiler-1.4.20.tar.gz.sha1
new file mode 100644
index 0000000..a2f45a8
--- /dev/null
+++ b/third_party/kotlin/kotlin-compiler-1.4.20.tar.gz.sha1
@@ -0,0 +1 @@
+8f0e34c232dc84ab65a589c514b7e33a19f87cc9
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-11/Linux.tar.gz.sha1 b/third_party/openjdk/jdk-11/Linux.tar.gz.sha1
deleted file mode 100644
index 7b3bb4e..0000000
--- a/third_party/openjdk/jdk-11/Linux.tar.gz.sha1
+++ /dev/null
@@ -1 +0,0 @@
-63d8982af46e1300e617ec3b266d44209ad38ffd
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-11/Mac.tar.gz.sha1 b/third_party/openjdk/jdk-11/Mac.tar.gz.sha1
deleted file mode 100644
index f95676e..0000000
--- a/third_party/openjdk/jdk-11/Mac.tar.gz.sha1
+++ /dev/null
@@ -1 +0,0 @@
-0e44bc7f7029397681fb6822729785887d565339
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-11/Windows.tar.gz.sha1 b/third_party/openjdk/jdk-11/Windows.tar.gz.sha1
deleted file mode 100644
index ee3ec56..0000000
--- a/third_party/openjdk/jdk-11/Windows.tar.gz.sha1
+++ /dev/null
@@ -1 +0,0 @@
-f332709d19bd53e8ceee3b5bd82b6355d00c9ae9
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-11/linux.tar.gz.sha1 b/third_party/openjdk/jdk-11/linux.tar.gz.sha1
new file mode 100644
index 0000000..4b310c1
--- /dev/null
+++ b/third_party/openjdk/jdk-11/linux.tar.gz.sha1
@@ -0,0 +1 @@
+b6f2e70af4adce81ddd3fd72778dcad442b01864
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-11/osx.tar.gz.sha1 b/third_party/openjdk/jdk-11/osx.tar.gz.sha1
new file mode 100644
index 0000000..13c2e79
--- /dev/null
+++ b/third_party/openjdk/jdk-11/osx.tar.gz.sha1
@@ -0,0 +1 @@
+4212f0fcd33202e7ae1ea6a4d10cdedeb3c166b4
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-11/windows.tar.gz.sha1 b/third_party/openjdk/jdk-11/windows.tar.gz.sha1
new file mode 100644
index 0000000..acd4eb7
--- /dev/null
+++ b/third_party/openjdk/jdk-11/windows.tar.gz.sha1
@@ -0,0 +1 @@
+c190e8fb2715e30dc5a30c765dd11321c852d56f
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-15/linux.tar.gz.sha1 b/third_party/openjdk/jdk-15/linux.tar.gz.sha1
new file mode 100644
index 0000000..2ac250c
--- /dev/null
+++ b/third_party/openjdk/jdk-15/linux.tar.gz.sha1
@@ -0,0 +1 @@
+116e48c5fcecdeccd6e26c07062298cdc3121ed7
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-15/osx.tar.gz.sha1 b/third_party/openjdk/jdk-15/osx.tar.gz.sha1
new file mode 100644
index 0000000..0393063
--- /dev/null
+++ b/third_party/openjdk/jdk-15/osx.tar.gz.sha1
@@ -0,0 +1 @@
+ca8935fb824a4d79a987396b3f268f0ecb1bd51b
\ No newline at end of file
diff --git a/third_party/openjdk/jdk-15/windows.tar.gz.sha1 b/third_party/openjdk/jdk-15/windows.tar.gz.sha1
new file mode 100644
index 0000000..6f3c8dc
--- /dev/null
+++ b/third_party/openjdk/jdk-15/windows.tar.gz.sha1
@@ -0,0 +1 @@
+b0c7e22d73b9c5751ef8b62f8a9b10afe8aafa61
\ No newline at end of file
diff --git a/tools/asmifier.py b/tools/asmifier.py
index 5290f0a..8aeb9a7 100755
--- a/tools/asmifier.py
+++ b/tools/asmifier.py
@@ -10,7 +10,7 @@
import sys
import utils
-ASM_VERSION = '8.0'
+ASM_VERSION = '9.0'
ASM_JAR = 'asm-' + ASM_VERSION + '.jar'
ASM_UTIL_JAR = 'asm-util-' + ASM_VERSION + '.jar'
diff --git a/tools/git_sync_cl_chain.py b/tools/git_sync_cl_chain.py
index f3a0728..857aab8 100755
--- a/tools/git_sync_cl_chain.py
+++ b/tools/git_sync_cl_chain.py
@@ -142,7 +142,9 @@
def delete_branches(branches):
assert len(branches) > 0
- utils.RunCmd(['git', 'branch', '-D'].extend(branches), quiet=True)
+ cmd = ['git', 'branch', '-D']
+ cmd.extend(branches)
+ utils.RunCmd(cmd, quiet=True)
def get_branch_with_name(name, branches):
for branch in branches:
diff --git a/tools/test.py b/tools/test.py
index 0c70124..cf14685 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -156,6 +156,11 @@
'--print-obfuscated-stacktraces', '--print_obfuscated_stacktraces',
default=False, action='store_true',
help='Print the obfuscated stacktraces')
+ result.add_option(
+ '--debug-agent', '--debug_agent',
+ help='Enable Java debug agent and suspend compilation (default disabled)',
+ default=False,
+ action='store_true')
return result.parse_args()
def archive_failures():
@@ -253,6 +258,8 @@
if options.worktree:
gradle_args.append('-g=' + os.path.join(utils.REPO_ROOT, ".gradle_user_home"))
gradle_args.append('--no-daemon')
+ if options.debug_agent:
+ gradle_args.append('--no-daemon')
# Build an R8 with dependencies for bootstrapping tests before adding test sources.
gradle_args.append('r8WithDeps')
@@ -263,6 +270,8 @@
# Add Gradle tasks
gradle_args.append('cleanTest')
gradle_args.append('test')
+ if options.debug_agent:
+ gradle_args.append('--debug-jvm')
if options.fail_fast:
gradle_args.append('--fail-fast')
if options.failed: