Merge commit '10ab5636bdbb856529f8e00ecb63da7cc6c5685b' into dev-release
diff --git a/build.gradle b/build.gradle
index 1077080..433b39a 100644
--- a/build.gradle
+++ b/build.gradle
@@ -43,6 +43,8 @@
gsonVersion = '2.7'
junitVersion = '4.13-beta-2'
mockitoVersion = '2.10.0'
+ // The kotlin version is only here to specify the kotlin language level,
+ // all kotlin compilations are done in tests.
kotlinVersion = '1.3.72'
kotlinExtMetadataJVMVersion = '0.1.0'
smaliVersion = '2.2b4'
@@ -148,12 +150,6 @@
srcDirs = ['src/test/testngrunner']
}
}
- examplesKotlin {
- java {
- srcDirs = ['src/test/examplesKotlin']
- }
- output.resourcesDir = 'build/classes/examplesKotlin'
- }
examplesAndroidN {
java {
srcDirs = ['src/test/examplesAndroidN']
@@ -274,7 +270,6 @@
supportLibs "com.android.support.test.espresso:espresso-core:$espressoVersion"
apiUsageSampleCompile sourceSets.main.output
apiUsageSampleCompile "com.google.guava:guava:$guavaVersion"
- examplesKotlinCompileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
kotlinR8TestResourcesCompileOnly "org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion"
errorprone("com.google.errorprone:error_prone_core:$errorproneVersion")
testImplementation "org.jetbrains.kotlin:kotlin-reflect:1.3.31"
@@ -1229,18 +1224,6 @@
targetCompatibility = JavaVersion.VERSION_1_8
}
-task buildExampleKotlinJars {
- def kotlinSrcDir = file("src/test/examplesKotlin")
- kotlinSrcDir.eachDir { dir ->
- def name = dir.getName();
- dependsOn "compile_example_kotlin_${name}"
- task "compile_example_kotlin_${name}"(type: kotlin.Kotlinc) {
- source = fileTree(dir: file("src/test/examplesKotlin/${name}"), include: '**/*.kt')
- destination = file("build/test/examplesKotlin/${name}.jar")
- }
- }
-}
-
task buildProtoGeneratedSources {
def examplesProtoDir = file("src/test/examplesProto")
examplesProtoDir.eachDir { dir ->
@@ -1622,52 +1605,15 @@
}
}
-task buildExamplesKotlin {
- if (OperatingSystem.current().isMacOsX() || OperatingSystem.current().isWindows()) {
- logger.lifecycle("WARNING: Testing (including building kotlin examples) is only partially" +
- " supported on your platform (" + OperatingSystem.current().getName() + ").")
- } else if (!OperatingSystem.current().isLinux()) {
- logger.lifecycle("WARNING: Testing (including building kotlin examples) is not supported " +
- "on your platform. It is fully supported on Linux and partially supported on " +
- "Mac OS and Windows")
- return;
- }
- def examplesDir = file("src/test/examplesKotlin")
- examplesDir.eachDir { dir ->
- def name = dir.getName();
- dependsOn "dex_example_kotlin_${name}"
- def exampleOutputDir = file("build/test/examplesKotlin/" + name);
- def dexPath = file("${exampleOutputDir}")
- task "dex_example_kotlin_${name}"(type: DxTask,
- dependsOn: "compile_example_kotlin_${name}") {
- doFirst {
- if (!dexPath.exists()) {
- dexPath.mkdirs()
- }
- }
- source = files(tasks.getByPath("compile_example_kotlin_${name}")).asFileTree
- destination = dexPath
- debug = false
- }
- }
-}
-
task buildKotlinR8TestResources {
def examplesDir = file("src/test/kotlinR8TestResources")
examplesDir.eachDir { dir ->
kotlin.Kotlinc.KotlinTargetVersion.values().each { kotlinTargetVersion ->
def name = dir.getName()
def taskName = "jar_kotlinR8TestResources_${name}_${kotlinTargetVersion}"
- def outputFile = "build/test/kotlinR8TestResources/${kotlinTargetVersion}/${name}.jar"
def javaOutput = "build/test/kotlinR8TestResources/${kotlinTargetVersion}/${name}/java"
def javaOutputJarName = "${name}.java.jar"
def javaOutputJarDir = "build/test/kotlinR8TestResources/${kotlinTargetVersion}"
- task "${taskName}Kotlin"(type: kotlin.Kotlinc) {
- source = fileTree(dir: file("${examplesDir}/${name}"),
- include: ['**/*.kt', '**/*.java'])
- destination = file(outputFile)
- targetVersion = kotlinTargetVersion
- }
task "${taskName}Java"(type: JavaCompile) {
source = fileTree(dir: file("${examplesDir}/${name}"), include: '**/*.java')
destinationDir = file(javaOutput)
@@ -1682,7 +1628,7 @@
from javaOutput
include "**/*.class"
}
- dependsOn "${taskName}Kotlin", "${taskName}JavaJar"
+ dependsOn "${taskName}JavaJar"
}
}
}
@@ -2101,7 +2047,6 @@
}
dependsOn downloadDeps
dependsOn buildExamples
- dependsOn buildExamplesKotlin
dependsOn buildKotlinR8TestResources
dependsOn buildSmali
dependsOn jctfCommonJar
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 3ebf03f..5960a22 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -140,6 +140,15 @@
}
}
builders {
+ name: "desugared_library_head"
+ mixins: "linux"
+ mixins: "normal"
+ priority: 26
+ recipe {
+ properties_j: "test_options:[\"--desugared-library\", \"HEAD\"]"
+ }
+ }
+ builders {
name: "linux"
mixins: "linux"
mixins: "normal"
diff --git a/infra/config/global/luci-milo.cfg b/infra/config/global/luci-milo.cfg
index 7400340..2cf08a6 100644
--- a/infra/config/global/luci-milo.cfg
+++ b/infra/config/global/luci-milo.cfg
@@ -96,6 +96,11 @@
short_name: "sdk_desugar"
}
builders {
+ name: "buildbucket/luci.r8.ci/desugared_library_head"
+ category: "archive_desugar"
+ short_name: "head_desugar"
+ }
+ builders {
name: "buildbucket/luci.r8.ci/archive_release"
category: "release archive"
short_name: "archive"
diff --git a/infra/config/global/luci-scheduler.cfg b/infra/config/global/luci-scheduler.cfg
index af1ff68..5e0355e 100644
--- a/infra/config/global/luci-scheduler.cfg
+++ b/infra/config/global/luci-scheduler.cfg
@@ -42,6 +42,7 @@
triggers: "linux-jctf"
triggers: "r8cf-linux-jctf"
triggers: "windows"
+ triggers: "desugared_library_head"
}
trigger {
@@ -145,6 +146,20 @@
}
job {
+ id: "desugared_library_head"
+ acl_sets: "default"
+ triggering_policy: {
+ max_concurrent_invocations: 1
+ max_batch_size: 1
+ }
+ buildbucket {
+ server: "cr-buildbucket.appspot.com"
+ bucket: "luci.r8.ci"
+ builder: "desugared_library_head"
+ }
+}
+
+job {
id: "kotlin-builder"
acl_sets: "default"
triggering_policy: {
diff --git a/src/main/java/com/android/tools/r8/DexIndexedConsumer.java b/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
index ec1f516..30093b5 100644
--- a/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
+++ b/src/main/java/com/android/tools/r8/DexIndexedConsumer.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.utils.ArchiveBuilder;
+import com.android.tools.r8.utils.DexUtils;
import com.android.tools.r8.utils.DirectoryBuilder;
import com.android.tools.r8.utils.ExceptionDiagnostic;
import com.android.tools.r8.utils.FileUtils;
@@ -88,16 +89,6 @@
this.consumer = consumer;
}
- protected static String getDefaultDexFileName(int fileIndex) {
- return fileIndex == 0
- ? "classes" + FileUtils.DEX_EXTENSION
- : ("classes" + (fileIndex + 1) + FileUtils.DEX_EXTENSION);
- }
-
- protected String getDexFileName(int fileIndex) {
- return getDefaultDexFileName(fileIndex);
- }
-
@Override
public DataResourceConsumer getDataResourceConsumer() {
return consumer != null ? consumer.getDataResourceConsumer() : null;
@@ -162,7 +153,8 @@
public void accept(
int fileIndex, ByteDataView data, Set<String> descriptors, DiagnosticsHandler handler) {
super.accept(fileIndex, data, descriptors, handler);
- outputBuilder.addIndexedClassFile(fileIndex, getDexFileName(fileIndex), data, handler);
+ outputBuilder.addIndexedClassFile(
+ fileIndex, DexUtils.getDefaultDexFileName(fileIndex), data, handler);
}
@Override
@@ -192,7 +184,7 @@
new BufferedOutputStream(Files.newOutputStream(archive, options)))) {
for (int i = 0; i < resources.size(); i++) {
ProgramResource resource = resources.get(i);
- String entryName = getDefaultDexFileName(i);
+ String entryName = DexUtils.getDefaultDexFileName(i);
byte[] bytes = ByteStreams.toByteArray(closer.register(resource.getByteStream()));
ZipUtils.writeToZipStream(out, entryName, bytes, ZipEntry.STORED);
}
@@ -253,7 +245,7 @@
} catch (IOException e) {
handler.error(new ExceptionDiagnostic(e, new PathOrigin(directory)));
}
- outputBuilder.addFile(getDexFileName(fileIndex), data, handler);
+ outputBuilder.addFile(DexUtils.getDefaultDexFileName(fileIndex), data, handler);
}
@Override
@@ -303,7 +295,7 @@
}
private static Path getTargetDexFile(Path directory, int fileIndex) {
- return directory.resolve(ForwardingConsumer.getDefaultDexFileName(fileIndex));
+ return directory.resolve(DexUtils.getDefaultDexFileName(fileIndex));
}
private static void writeFile(byte[] contents, Path target) throws IOException {
diff --git a/src/main/java/com/android/tools/r8/StringConsumer.java b/src/main/java/com/android/tools/r8/StringConsumer.java
index 1cd6718..843d145 100644
--- a/src/main/java/com/android/tools/r8/StringConsumer.java
+++ b/src/main/java/com/android/tools/r8/StringConsumer.java
@@ -64,7 +64,8 @@
}
/** Forwarding consumer to delegate to an optional existing consumer. */
- class ForwardingConsumer implements StringConsumer {
+ @Keep
+ public class ForwardingConsumer implements StringConsumer {
private final StringConsumer consumer;
diff --git a/src/main/java/com/android/tools/r8/annotations/SynthesizedClassMap.java b/src/main/java/com/android/tools/r8/annotations/SynthesizedClassMap.java
deleted file mode 100644
index b46a2ba..0000000
--- a/src/main/java/com/android/tools/r8/annotations/SynthesizedClassMap.java
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) 2017, 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.annotations;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Retention(RetentionPolicy.CLASS)
-@Target(ElementType.TYPE)
-public @interface SynthesizedClassMap {
- Class<?>[] value() default {};
-}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
index 259ad12..7ce2440 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrameVerificationHelper.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.graph.CfCodeStackMapValidatingException;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.utils.MapUtils;
import com.android.tools.r8.utils.collections.ImmutableDeque;
import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
@@ -37,6 +38,7 @@
private final BiPredicate<DexType, DexType> isJavaAssignable;
private final DexItemFactory factory;
private final List<CfTryCatch> tryCatchRanges;
+ private final GraphLens graphLens;
private final Deque<CfTryCatch> currentCatchRanges = new ArrayDeque<>();
private final Set<CfLabel> tryCatchRangeLabels;
@@ -46,12 +48,14 @@
Map<CfLabel, CfFrame> stateMap,
List<CfTryCatch> tryCatchRanges,
BiPredicate<DexType, DexType> isJavaAssignable,
- DexItemFactory factory) {
+ DexItemFactory factory,
+ GraphLens graphLens) {
this.context = context;
this.stateMap = stateMap;
this.tryCatchRanges = tryCatchRanges;
this.isJavaAssignable = isJavaAssignable;
this.factory = factory;
+ this.graphLens = graphLens;
throwStack = ImmutableDeque.of(FrameType.initialized(factory.throwableType));
// Compute all labels that marks a start or end to catch ranges.
tryCatchRangeLabels = Sets.newIdentityHashSet();
@@ -230,10 +234,11 @@
public void verifyIsAssignable(FrameType source, DexType target) {
if (!source.isInitialized()) {
- if (source.isUninitializedThis() && target == context) {
+ DexType rewrittenTarget = graphLens.lookupClassType(target);
+ if (source.isUninitializedThis() && rewrittenTarget == context) {
return;
}
- if (target == factory.objectType) {
+ if (rewrittenTarget == factory.objectType) {
return;
}
throw CfCodeStackMapValidatingException.error(
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index 614ac4d..135fcb4 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -401,9 +401,7 @@
VirtualFile mainDexFile = virtualFiles.get(0);
mainDexInfo.forEach(
type -> {
- // TODO(b/178577273): We should ensure only live types in main dex.
- DexProgramClass clazz =
- asProgramClassOrNull(appView.appInfo().definitionForWithoutExistenceAssert(type));
+ DexProgramClass clazz = asProgramClassOrNull(appView.appInfo().definitionFor(type));
if (clazz != null) {
mainDexFile.addClass(clazz);
classes.remove(clazz);
diff --git a/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionInfo.java b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionInfo.java
index c2905ce..ec486de 100644
--- a/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionInfo.java
+++ b/src/main/java/com/android/tools/r8/diagnostic/MissingDefinitionInfo.java
@@ -64,6 +64,9 @@
return null;
}
+ /** User friendly description of the missing definition. */
+ String getDiagnosticMessage();
+
/** The contexts from which this missing definition was referenced. */
Collection<MissingDefinitionContext> getReferencedFromContexts();
}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoBase.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoBase.java
index 0f9e655..b3d2872 100644
--- a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoBase.java
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoBase.java
@@ -18,6 +18,13 @@
}
@Override
+ public String getDiagnosticMessage() {
+ StringBuilder builder = new StringBuilder();
+ MissingDefinitionInfoUtils.writeDiagnosticMessage(builder, this);
+ return builder.toString();
+ }
+
+ @Override
public final Collection<MissingDefinitionContext> getReferencedFromContexts() {
return referencedFromContexts;
}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoUtils.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoUtils.java
index b94dbf1..34f2f2c 100644
--- a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoUtils.java
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionInfoUtils.java
@@ -4,13 +4,19 @@
package com.android.tools.r8.diagnostic.internal;
+import static com.android.tools.r8.utils.ClassReferenceUtils.getClassReferenceComparator;
+import static com.android.tools.r8.utils.FieldReferenceUtils.getFieldReferenceComparator;
+import static com.android.tools.r8.utils.MethodReferenceUtils.getMethodReferenceComparator;
+
import com.android.tools.r8.diagnostic.MissingClassInfo;
+import com.android.tools.r8.diagnostic.MissingDefinitionContext;
import com.android.tools.r8.diagnostic.MissingDefinitionInfo;
import com.android.tools.r8.diagnostic.MissingFieldInfo;
import com.android.tools.r8.diagnostic.MissingMethodInfo;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.MethodReference;
+import com.android.tools.r8.utils.Box;
import com.android.tools.r8.utils.ClassReferenceUtils;
import com.android.tools.r8.utils.FieldReferenceUtils;
import com.android.tools.r8.utils.MethodReferenceUtils;
@@ -77,4 +83,65 @@
public static Comparator<MissingDefinitionInfo> getComparator() {
return COMPARATOR;
}
+
+ public static void writeDiagnosticMessage(
+ StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo) {
+ builder.append("Missing class ");
+ MissingDefinitionInfoUtils.accept(
+ missingDefinitionInfo,
+ missingClassInfo -> builder.append(missingClassInfo.getClassReference().getTypeName()),
+ missingFieldInfo ->
+ builder.append(
+ FieldReferenceUtils.toSourceString(missingFieldInfo.getFieldReference())),
+ missingMethodInfo ->
+ builder.append(
+ MethodReferenceUtils.toSourceString(missingMethodInfo.getMethodReference())));
+ writeReferencedFromSuffix(builder, missingDefinitionInfo);
+ }
+
+ private static void writeReferencedFromSuffix(
+ StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo) {
+ Box<ClassReference> classContext = new Box<>();
+ Box<FieldReference> fieldContext = new Box<>();
+ Box<MethodReference> methodContext = new Box<>();
+ for (MissingDefinitionContext missingDefinitionContext :
+ missingDefinitionInfo.getReferencedFromContexts()) {
+ MissingDefinitionContextUtils.accept(
+ missingDefinitionContext,
+ missingDefinitionClassContext ->
+ classContext.setMin(
+ missingDefinitionClassContext.getClassReference(), getClassReferenceComparator()),
+ missingDefinitionFieldContext ->
+ fieldContext.setMin(
+ missingDefinitionFieldContext.getFieldReference(), getFieldReferenceComparator()),
+ missingDefinitionMethodContext ->
+ methodContext.setMin(
+ missingDefinitionMethodContext.getMethodReference(),
+ getMethodReferenceComparator()));
+ }
+ assert classContext.isSet() || fieldContext.isSet() || methodContext.isSet();
+ if (fieldContext.isSet()) {
+ writeReferencedFromSuffix(
+ builder, missingDefinitionInfo, FieldReferenceUtils.toSourceString(fieldContext.get()));
+ } else if (methodContext.isSet()) {
+ writeReferencedFromSuffix(
+ builder, missingDefinitionInfo, MethodReferenceUtils.toSourceString(methodContext.get()));
+ } else {
+ writeReferencedFromSuffix(builder, missingDefinitionInfo, classContext.get().getTypeName());
+ }
+ }
+
+ private static void writeReferencedFromSuffix(
+ StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo, String referencedFrom) {
+ int numberOfOtherContexts = missingDefinitionInfo.getReferencedFromContexts().size() - 1;
+ assert numberOfOtherContexts >= 0;
+ builder.append(" (referenced from: ").append(referencedFrom);
+ if (numberOfOtherContexts >= 1) {
+ builder.append(" and ").append(numberOfOtherContexts).append(" other context");
+ if (numberOfOtherContexts >= 2) {
+ builder.append("s");
+ }
+ }
+ builder.append(")");
+ }
}
diff --git a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionsDiagnosticImpl.java b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionsDiagnosticImpl.java
index 7be87b6..a180ed2 100644
--- a/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionsDiagnosticImpl.java
+++ b/src/main/java/com/android/tools/r8/diagnostic/internal/MissingDefinitionsDiagnosticImpl.java
@@ -4,21 +4,10 @@
package com.android.tools.r8.diagnostic.internal;
-import static com.android.tools.r8.utils.ClassReferenceUtils.getClassReferenceComparator;
-import static com.android.tools.r8.utils.FieldReferenceUtils.getFieldReferenceComparator;
-import static com.android.tools.r8.utils.MethodReferenceUtils.getMethodReferenceComparator;
-
-import com.android.tools.r8.diagnostic.MissingDefinitionContext;
import com.android.tools.r8.diagnostic.MissingDefinitionInfo;
import com.android.tools.r8.diagnostic.MissingDefinitionsDiagnostic;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
-import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.FieldReference;
-import com.android.tools.r8.references.MethodReference;
-import com.android.tools.r8.utils.Box;
-import com.android.tools.r8.utils.FieldReferenceUtils;
-import com.android.tools.r8.utils.MethodReferenceUtils;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Collection;
@@ -40,12 +29,12 @@
@Override
public Collection<MissingDefinitionInfo> getMissingDefinitions() {
- return missingDefinitions;
+ return getMissingDefinitionsWithDeterministicOrder();
}
private Collection<MissingDefinitionInfo> getMissingDefinitionsWithDeterministicOrder() {
List<MissingDefinitionInfo> missingDefinitionsWithDeterministicOrder =
- new ArrayList<>(getMissingDefinitions());
+ new ArrayList<>(missingDefinitions);
missingDefinitionsWithDeterministicOrder.sort(MissingDefinitionInfoUtils.getComparator());
return missingDefinitionsWithDeterministicOrder;
}
@@ -72,78 +61,17 @@
assert missingDefinitionsIterator.hasNext();
// Write first line.
- writeMissingDefinition(builder.append("Missing class "), missingDefinitionsIterator.next());
+ MissingDefinitionInfoUtils.writeDiagnosticMessage(builder, missingDefinitionsIterator.next());
// Write remaining lines with line separator before.
missingDefinitionsIterator.forEachRemaining(
missingDefinition ->
- writeMissingDefinition(
- builder.append(System.lineSeparator()).append("Missing class "),
- missingDefinition));
+ MissingDefinitionInfoUtils.writeDiagnosticMessage(
+ builder.append(System.lineSeparator()), missingDefinition));
return builder.toString();
}
- private static void writeMissingDefinition(
- StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo) {
- MissingDefinitionInfoUtils.accept(
- missingDefinitionInfo,
- missingClassInfo -> builder.append(missingClassInfo.getClassReference().getTypeName()),
- missingFieldInfo ->
- builder.append(
- FieldReferenceUtils.toSourceString(missingFieldInfo.getFieldReference())),
- missingMethodInfo ->
- builder.append(
- MethodReferenceUtils.toSourceString(missingMethodInfo.getMethodReference())));
- writeReferencedFromSuffix(builder, missingDefinitionInfo);
- }
-
- private static void writeReferencedFromSuffix(
- StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo) {
- Box<ClassReference> classContext = new Box<>();
- Box<FieldReference> fieldContext = new Box<>();
- Box<MethodReference> methodContext = new Box<>();
- for (MissingDefinitionContext missingDefinitionContext :
- missingDefinitionInfo.getReferencedFromContexts()) {
- MissingDefinitionContextUtils.accept(
- missingDefinitionContext,
- missingDefinitionClassContext ->
- classContext.setMin(
- missingDefinitionClassContext.getClassReference(), getClassReferenceComparator()),
- missingDefinitionFieldContext ->
- fieldContext.setMin(
- missingDefinitionFieldContext.getFieldReference(), getFieldReferenceComparator()),
- missingDefinitionMethodContext ->
- methodContext.setMin(
- missingDefinitionMethodContext.getMethodReference(),
- getMethodReferenceComparator()));
- }
- assert classContext.isSet() || fieldContext.isSet() || methodContext.isSet();
- if (fieldContext.isSet()) {
- writeReferencedFromSuffix(
- builder, missingDefinitionInfo, FieldReferenceUtils.toSourceString(fieldContext.get()));
- } else if (methodContext.isSet()) {
- writeReferencedFromSuffix(
- builder, missingDefinitionInfo, MethodReferenceUtils.toSourceString(methodContext.get()));
- } else {
- writeReferencedFromSuffix(builder, missingDefinitionInfo, classContext.get().getTypeName());
- }
- }
-
- private static void writeReferencedFromSuffix(
- StringBuilder builder, MissingDefinitionInfo missingDefinitionInfo, String referencedFrom) {
- int numberOfOtherContexts = missingDefinitionInfo.getReferencedFromContexts().size() - 1;
- assert numberOfOtherContexts >= 0;
- builder.append(" (referenced from: ").append(referencedFrom);
- if (numberOfOtherContexts >= 1) {
- builder.append(", and ").append(numberOfOtherContexts).append(" other context");
- if (numberOfOtherContexts >= 2) {
- builder.append("s");
- }
- }
- builder.append(")");
- }
-
public static class Builder {
private ImmutableList.Builder<MissingDefinitionInfo> missingDefinitionsBuilder =
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index 337ec1d..ed43ca9 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -305,9 +305,7 @@
LensCodeRewriterUtils rewriter,
MethodVisitor visitor) {
GraphLens graphLens = appView.graphLens();
- // TODO(b/170073151): Handle unapplied code rewritings.
- assert graphLens.hasCodeRewritings()
- || verifyFrames(method.getDefinition(), appView, null, false);
+ assert verifyFrames(method.getDefinition(), appView, null, false);
DexItemFactory dexItemFactory = appView.dexItemFactory();
InitClassLens initClassLens = appView.initClassLens();
InternalOptions options = appView.options();
@@ -791,7 +789,8 @@
stateMap,
tryCatchRanges,
isAssignablePredicate(appView),
- appView.dexItemFactory());
+ appView.dexItemFactory(),
+ appView.graphLens());
if (stateMap.containsKey(null)) {
assert !shouldComputeInitialFrame();
builder.verifyFrameAndSet(stateMap.get(null));
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
index 3483fbb..f2959bb 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java
@@ -5,7 +5,6 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
-import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.graph.DexValue.DexValueAnnotation;
import com.android.tools.r8.graph.DexValue.DexValueArray;
import com.android.tools.r8.graph.DexValue.DexValueInt;
@@ -22,10 +21,7 @@
import com.android.tools.r8.utils.structural.StructuralMapping;
import com.android.tools.r8.utils.structural.StructuralSpecification;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
import java.util.List;
-import java.util.TreeSet;
import java.util.function.Function;
public class DexAnnotation extends DexItem implements StructuralItem<DexAnnotation> {
@@ -96,8 +92,7 @@
}
if (annotation == options.itemFactory.dalvikFastNativeAnnotation
|| annotation == options.itemFactory.dalvikCriticalNativeAnnotation
- || annotation == options.itemFactory.annotationSynthesizedClass
- || annotation == options.itemFactory.annotationSynthesizedClassMap) {
+ || annotation == options.itemFactory.annotationSynthesizedClass) {
return true;
}
if (options.processCovariantReturnTypeAnnotations) {
@@ -363,43 +358,6 @@
return new DexValueString(factory.createString(string));
}
- public static Collection<DexType> readAnnotationSynthesizedClassMap(
- DexProgramClass clazz, DexItemFactory dexItemFactory) {
- DexAnnotation foundAnnotation =
- clazz.annotations().getFirstMatching(dexItemFactory.annotationSynthesizedClassMap);
- if (foundAnnotation != null) {
- if (foundAnnotation.annotation.elements.length != 1) {
- throw new CompilationError(getInvalidSynthesizedClassMapMessage(clazz, foundAnnotation));
- }
- DexAnnotationElement value = foundAnnotation.annotation.elements[0];
- if (value.name != dexItemFactory.valueString) {
- throw new CompilationError(getInvalidSynthesizedClassMapMessage(clazz, foundAnnotation));
- }
- DexValueArray existingList = value.value.asDexValueArray();
- if (existingList == null) {
- throw new CompilationError(getInvalidSynthesizedClassMapMessage(clazz, foundAnnotation));
- }
- Collection<DexType> synthesized = new ArrayList<>(existingList.values.length);
- for (DexValue element : existingList.getValues()) {
- if (!element.isDexValueType()) {
- throw new CompilationError(getInvalidSynthesizedClassMapMessage(clazz, foundAnnotation));
- }
- synthesized.add(element.asDexValueType().value);
- }
- return synthesized;
- }
- return Collections.emptyList();
- }
-
- private static String getInvalidSynthesizedClassMapMessage(
- DexProgramClass annotatedClass,
- DexAnnotation invalidAnnotation) {
- return annotatedClass.toSourceString()
- + " is annotated with invalid "
- + invalidAnnotation.annotation.type.toString()
- + ": " + invalidAnnotation.toString();
- }
-
public static DexAnnotation createAnnotationSynthesizedClass(
SyntheticKind kind, DexType synthesizingContext, DexItemFactory dexItemFactory) {
DexAnnotationElement kindElement =
@@ -456,26 +414,6 @@
return new Pair<>(kind, valueElement.value.asDexValueType().getValue());
}
- public static DexAnnotation createAnnotationSynthesizedClassMap(
- TreeSet<DexType> synthesized,
- DexItemFactory dexItemFactory) {
- DexValueType[] values = synthesized.stream()
- .map(DexValueType::new)
- .toArray(DexValueType[]::new);
- DexValueArray array = new DexValueArray(values);
- DexAnnotationElement pair =
- new DexAnnotationElement(dexItemFactory.createString("value"), array);
- return new DexAnnotation(
- VISIBILITY_BUILD,
- new DexEncodedAnnotation(
- dexItemFactory.annotationSynthesizedClassMap, new DexAnnotationElement[]{pair}));
- }
-
- public static boolean isSynthesizedClassMapAnnotation(DexAnnotation annotation,
- DexItemFactory factory) {
- return annotation.annotation.type == factory.annotationSynthesizedClassMap;
- }
-
public DexAnnotation rewrite(Function<DexEncodedAnnotation, DexEncodedAnnotation> rewriter) {
DexEncodedAnnotation rewritten = rewriter.apply(annotation);
if (rewritten == annotation) {
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 afc04c7..5c9fc0f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -1184,6 +1184,9 @@
return this;
}
Builder builder = builder(this);
+ if (isNonPrivateVirtualMethod() && isLibraryMethodOverride() != OptionalBool.unknown()) {
+ builder.setIsLibraryMethodOverride(isLibraryMethodOverride());
+ }
builder.setMethod(method);
// TODO(b/112847660): Fix type fixers that use this method: Class staticizer
// TODO(b/112847660): Fix type fixers that use this method: Uninstantiated type optimization
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 0752d20..e76409d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -605,8 +605,6 @@
public final DexType annotationThrows = createStaticallyKnownType("Ldalvik/annotation/Throws;");
public final DexType annotationSynthesizedClass =
createStaticallyKnownType("Lcom/android/tools/r8/annotations/SynthesizedClass;");
- public final DexType annotationSynthesizedClassMap =
- createStaticallyKnownType("Lcom/android/tools/r8/annotations/SynthesizedClassMap;");
public final DexType annotationCovariantReturnType =
createStaticallyKnownType("Ldalvik/annotation/codegen/CovariantReturnType;");
public final DexType annotationCovariantReturnTypes =
@@ -638,6 +636,7 @@
public final DexType comparableType = createStaticallyKnownType("Ljava/lang/Comparable;");
public final DexType stringConcatFactoryType =
createStaticallyKnownType("Ljava/lang/invoke/StringConcatFactory;");
+ public final DexType unsafeType = createStaticallyKnownType("Lsun/misc/Unsafe;");
public final ServiceLoaderMethods serviceLoaderMethods = new ServiceLoaderMethods();
public final StringConcatFactoryMembers stringConcatFactoryMembers =
@@ -2330,8 +2329,17 @@
MethodHandleType type,
DexMember<? extends DexItem, ? extends DexMember<?, ?>> fieldOrMethod,
boolean isInterface) {
+ return createMethodHandle(type, fieldOrMethod, isInterface, null);
+ }
+
+ public DexMethodHandle createMethodHandle(
+ MethodHandleType type,
+ DexMember<? extends DexItem, ? extends DexMember<?, ?>> fieldOrMethod,
+ boolean isInterface,
+ DexMethod rewrittenTarget) {
assert !sorted;
- DexMethodHandle methodHandle = new DexMethodHandle(type, fieldOrMethod, isInterface);
+ DexMethodHandle methodHandle =
+ new DexMethodHandle(type, fieldOrMethod, isInterface, rewrittenTarget);
return canonicalize(methodHandles, methodHandle);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
index 0bdb208..71bc104 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
@@ -207,13 +207,6 @@
public DexMethodHandle(
MethodHandleType type,
DexMember<? extends DexItem, ? extends DexMember<?, ?>> member,
- boolean isInterface) {
- this(type, member, isInterface, null);
- }
-
- public DexMethodHandle(
- MethodHandleType type,
- DexMember<? extends DexItem, ? extends DexMember<?, ?>> member,
boolean isInterface,
DexMethod rewrittenTarget) {
this.type = type;
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractState.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractState.java
index 673411a..68b456b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractState.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/AbstractState.java
@@ -12,6 +12,11 @@
public abstract StateType join(StateType state);
+ public boolean isGreaterThanOrEquals(StateType state) {
+ StateType leastUpperBound = join(state);
+ return equals(leastUpperBound);
+ }
+
@Override
public abstract boolean equals(Object other);
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/DataflowAnalysisResult.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/DataflowAnalysisResult.java
index 68a8a24..701df38 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/DataflowAnalysisResult.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/DataflowAnalysisResult.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.ir.analysis.framework.intraprocedural;
import com.android.tools.r8.ir.code.BasicBlock;
+import java.util.Map;
/**
* The result returned by {@link IntraproceduralDataflowAnalysis#run(BasicBlock)}.
@@ -23,16 +24,34 @@
return false;
}
+ public <StateType extends AbstractState<StateType>>
+ SuccessfulDataflowAnalysisResult<StateType> asSuccessfulAnalysisResult() {
+ return null;
+ }
+
public boolean isFailedAnalysisResult() {
return false;
}
- public static class SuccessfulDataflowAnalysisResult extends DataflowAnalysisResult {
+ public static class SuccessfulDataflowAnalysisResult<StateType extends AbstractState<StateType>>
+ extends DataflowAnalysisResult {
+
+ private final Map<BasicBlock, StateType> blockExitStates;
+
+ public SuccessfulDataflowAnalysisResult(Map<BasicBlock, StateType> blockExitStates) {
+ this.blockExitStates = blockExitStates;
+ }
@Override
public boolean isSuccessfulAnalysisResult() {
return true;
}
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public SuccessfulDataflowAnalysisResult<StateType> asSuccessfulAnalysisResult() {
+ return this;
+ }
}
public static class FailedDataflowAnalysisResult extends DataflowAnalysisResult {
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraproceduralDataflowAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraproceduralDataflowAnalysis.java
index a8482bb..c990bdb 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraproceduralDataflowAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/IntraproceduralDataflowAnalysis.java
@@ -45,37 +45,50 @@
private DataflowAnalysisResult run(WorkList<BasicBlock> worklist) {
while (worklist.hasNext()) {
BasicBlock block = worklist.next();
+ BasicBlock end = null;
// Compute the abstract state upon entry to the basic block, by joining all the predecessor
// exit states.
StateType state = computeBlockEntryState(block);
- for (Instruction instruction : block.getInstructions()) {
- TransferFunctionResult<StateType> transferResult = transfer.apply(instruction, state);
- if (transferResult.isFailedTransferResult()) {
- return new FailedDataflowAnalysisResult();
+ do {
+ for (Instruction instruction : block.getInstructions()) {
+ TransferFunctionResult<StateType> transferResult = transfer.apply(instruction, state);
+ if (transferResult.isFailedTransferResult()) {
+ return new FailedDataflowAnalysisResult();
+ }
+ assert transferResult.isAbstractState();
+ state = transferResult.asAbstractState();
}
- assert transferResult.isAbstractState();
- state = transferResult.asAbstractState();
- }
+ if (block.hasUniqueSuccessorWithUniquePredecessor()) {
+ block = block.getUniqueSuccessor();
+ } else {
+ end = block;
+ block = null;
+ }
+ } while (block != null);
// Update the block exit state, and re-enqueue all successor blocks if the abstract state
// changed.
- if (setBlockExitState(block, state)) {
- worklist.addAllIgnoringSeenSet(block.getSuccessors());
+ if (setBlockExitState(end, state)) {
+ worklist.addAllIgnoringSeenSet(end.getSuccessors());
}
}
- return new SuccessfulDataflowAnalysisResult();
+ return new SuccessfulDataflowAnalysisResult<>(blockExitStates);
}
private StateType computeBlockEntryState(BasicBlock block) {
StateType result = bottom;
for (BasicBlock predecessor : block.getPredecessors()) {
- StateType predecessorState = blockExitStates.getOrDefault(predecessor, bottom);
- result = result.join(predecessorState);
+ StateType edgeState =
+ transfer.computeBlockEntryState(
+ block, predecessor, blockExitStates.getOrDefault(predecessor, bottom));
+ result = result.join(edgeState);
}
return result;
}
private boolean setBlockExitState(BasicBlock block, StateType state) {
+ assert !block.hasUniqueSuccessorWithUniquePredecessor();
StateType previous = blockExitStates.put(block, state);
+ assert previous == null || state.isGreaterThanOrEquals(previous);
return !state.equals(previous);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/TransferFunction.java b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/TransferFunction.java
index 98ede7c..73c9470 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/TransferFunction.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/framework/intraprocedural/TransferFunction.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.analysis.framework.intraprocedural;
+import com.android.tools.r8.ir.code.BasicBlock;
import com.android.tools.r8.ir.code.Instruction;
/**
@@ -13,4 +14,9 @@
public interface TransferFunction<StateType extends AbstractState<StateType>> {
TransferFunctionResult<StateType> apply(Instruction instruction, StateType state);
+
+ default StateType computeBlockEntryState(
+ BasicBlock block, BasicBlock predecessor, StateType predecessorExitState) {
+ return predecessorExitState;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
index e81d765..7dbc0ad 100644
--- a/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
+++ b/src/main/java/com/android/tools/r8/ir/code/BasicBlock.java
@@ -190,6 +190,10 @@
return successors.size() == 1;
}
+ public boolean hasUniqueSuccessorWithUniquePredecessor() {
+ return hasUniqueSuccessor() && getUniqueSuccessor().getPredecessors().size() == 1;
+ }
+
public boolean hasUniqueNormalSuccessor() {
return numberOfNormalSuccessors() == 1;
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
index 4bc8714..b8a70f9 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
@@ -137,17 +137,21 @@
if (newType != oldType || actualTarget != invokedMethod || rewrittenTarget != actualTarget) {
DexClass holder = definitions.definitionFor(actualTarget.holder, context);
boolean isInterface = holder != null ? holder.isInterface() : methodHandle.isInterface;
- return new DexMethodHandle(
- newType,
- actualTarget,
- isInterface,
- rewrittenTarget != actualTarget ? rewrittenTarget : null);
+ return definitions
+ .dexItemFactory()
+ .createMethodHandle(
+ newType,
+ actualTarget,
+ isInterface,
+ rewrittenTarget != actualTarget ? rewrittenTarget : null);
}
} else {
DexField field = methodHandle.asField();
DexField actualField = graphLens().lookupField(field);
if (actualField != field) {
- return new DexMethodHandle(methodHandle.type, actualField, methodHandle.isInterface);
+ return definitions
+ .dexItemFactory()
+ .createMethodHandle(methodHandle.type, actualField, methodHandle.isInterface);
}
}
return methodHandle;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
index b1b14fb..0cdf967 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
@@ -60,6 +61,9 @@
void setBridgeInfo(DexEncodedMethod method, BridgeInfo bridgeInfo);
+ void setClassInlinerMethodConstraint(
+ ProgramMethod method, ClassInlinerMethodConstraint classInlinerConstraint);
+
void setClassInlinerEligibility(DexEncodedMethod method, ClassInlinerEligibilityInfo eligibility);
void setInstanceInitializerInfoCollection(
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 0d5cd1c..bd5c0b3 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -174,6 +174,9 @@
if (options.minApiLevel < AndroidApiLevel.R.getLevel()) {
initializeAndroidRMethodProviders(factory);
}
+ if (options.minApiLevel < AndroidApiLevel.S.getLevel()) {
+ initializeAndroidSMethodProviders(factory);
+ }
// The following providers are currently not implemented at any API level in Android.
// They however require the Optional/Stream class to be present, either through desugared
@@ -191,7 +194,6 @@
}
// These are currently not implemented at any API level in Android.
- initializeJava9MethodProviders(factory);
initializeJava10MethodProviders(factory);
initializeJava11MethodProviders(factory);
}
@@ -962,15 +964,49 @@
addProvider(new MethodGenerator(method, BackportedMethods::CollectionMethods_mapEntry));
}
- private void initializeJava9MethodProviders(DexItemFactory factory) {
+ private void initializeAndroidSMethodProviders(DexItemFactory factory) {
+ DexType type;
+ DexString name;
+ DexProto proto;
+ DexMethod method;
+
+ // Set
+ type = factory.setType;
+
+ // Set Set.copyOf(Collection)
+ name = factory.createString("copyOf");
+ proto = factory.createProto(factory.setType, factory.collectionType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(
+ new MethodGenerator(
+ method, BackportedMethods::CollectionsMethods_copyOfSet, "copyOfSet"));
+
+ // Byte
+ type = factory.boxedByteType;
+
+ // int Byte.compareUnsigned(byte, byte)
+ name = factory.createString("compareUnsigned");
+ proto = factory.createProto(factory.intType, factory.byteType, factory.byteType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(new MethodGenerator(method, BackportedMethods::ByteMethods_compareUnsigned));
+
+ // Short
+ type = factory.boxedShortType;
+
+ // int Short.compareUnsigned(short, short)
+ name = factory.createString("compareUnsigned");
+ proto = factory.createProto(factory.intType, factory.shortType, factory.shortType);
+ method = factory.createMethod(type, proto, name);
+ addProvider(new MethodGenerator(method, BackportedMethods::ShortMethods_compareUnsigned));
+
// Math & StrictMath, which have some symmetric, binary-compatible APIs
DexType[] mathTypes = {factory.mathType, factory.strictMathType};
for (DexType mathType : mathTypes) {
// long {Math,StrictMath}.multiplyExact(long, int)
- DexString name = factory.createString("multiplyExact");
- DexProto proto = factory.createProto(factory.longType, factory.longType, factory.intType);
- DexMethod method = factory.createMethod(mathType, proto, name);
+ name = factory.createString("multiplyExact");
+ proto = factory.createProto(factory.longType, factory.longType, factory.intType);
+ method = factory.createMethod(mathType, proto, name);
addProvider(
new MethodGenerator(
method,
@@ -1005,24 +1041,6 @@
new MethodGenerator(
method, BackportedMethods::MathMethods_floorModLongInt, "floorModLongInt"));
}
-
- // Byte
- DexType type = factory.boxedByteType;
-
- // int Byte.compareUnsigned(byte, byte)
- DexString name = factory.createString("compareUnsigned");
- DexProto proto = factory.createProto(factory.intType, factory.byteType, factory.byteType);
- DexMethod method = factory.createMethod(type, proto, name);
- addProvider(new MethodGenerator(method, BackportedMethods::ByteMethods_compareUnsigned));
-
- // Short
- type = factory.boxedShortType;
-
- // int Short.compareUnsigned(short, short)
- name = factory.createString("compareUnsigned");
- proto = factory.createProto(factory.intType, factory.shortType, factory.shortType);
- method = factory.createMethod(type, proto, name);
- addProvider(new MethodGenerator(method, BackportedMethods::ShortMethods_compareUnsigned));
}
private void initializeJava10MethodProviders(DexItemFactory factory) {
@@ -1037,18 +1055,7 @@
new MethodGenerator(
method, BackportedMethods::CollectionsMethods_copyOfList, "copyOfList"));
- // Set
- type = factory.setType;
-
- // Set Set.copyOf(Collection)
- name = factory.createString("copyOf");
- proto = factory.createProto(factory.setType, factory.collectionType);
- method = factory.createMethod(type, proto, name);
- addProvider(
- new MethodGenerator(
- method, BackportedMethods::CollectionsMethods_copyOfSet, "copyOfSet"));
-
- // Set
+ // Map
type = factory.mapType;
// Map Map.copyOf(Map)
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SwitchCaseEliminator.java b/src/main/java/com/android/tools/r8/ir/optimize/SwitchCaseEliminator.java
index 733db77..6c9bfbb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/SwitchCaseEliminator.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/SwitchCaseEliminator.java
@@ -83,20 +83,20 @@
boolean optimize() {
if (canBeOptimized()) {
int originalNumberOfSuccessors = block.getSuccessors().size();
- unlinkDeadSuccessors();
+ IntList removedSuccessorIndices = unlinkDeadSuccessors();
if (hasAlwaysHitCase() || allSwitchCasesMarkedForRemoval()) {
// Replace switch with a simple goto.
replaceSwitchByGoto();
} else {
// Replace switch by a new switch where the dead switch cases have been removed.
- replaceSwitchByOptimizedSwitch(originalNumberOfSuccessors);
+ replaceSwitchByOptimizedSwitch(originalNumberOfSuccessors, removedSuccessorIndices);
}
return true;
}
return false;
}
- private void unlinkDeadSuccessors() {
+ private IntList unlinkDeadSuccessors() {
IntPredicate successorHasBecomeDeadPredicate = computeSuccessorHasBecomeDeadPredicate();
IntList successorIndicesToBeRemoved = new IntArrayList();
for (int i = 0; i < block.getSuccessors().size(); i++) {
@@ -111,6 +111,7 @@
}
successorIndicesToBeRemoved.sort(Comparator.naturalOrder());
block.removeSuccessorsByIndex(successorIndicesToBeRemoved);
+ return successorIndicesToBeRemoved;
}
private IntPredicate computeSuccessorHasBecomeDeadPredicate() {
@@ -136,16 +137,12 @@
iterator.replaceCurrentInstruction(new Goto(target));
}
- private void replaceSwitchByOptimizedSwitch(int originalNumberOfSuccessors) {
+ private void replaceSwitchByOptimizedSwitch(
+ int originalNumberOfSuccessors, IntList removedSuccessorIndices) {
int[] targetBlockIndexOffset = new int[originalNumberOfSuccessors];
- for (int i : switchCasesToBeRemoved) {
- int targetBlockIndex = theSwitch.getTargetBlockIndex(i);
- // Add 1 because we are interested in the number of targets removed before a given index.
- if (targetBlockIndex + 1 < targetBlockIndexOffset.length) {
- targetBlockIndexOffset[targetBlockIndex + 1] = 1;
- }
+ for (int removedSuccessorIndex : removedSuccessorIndices) {
+ targetBlockIndexOffset[removedSuccessorIndex] = 1;
}
-
for (int i = 1; i < targetBlockIndexOffset.length; i++) {
targetBlockIndexOffset[i] += targetBlockIndexOffset[i - 1];
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java
index 35eaaf5..78e756d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerEligibilityInfo.java
@@ -21,8 +21,8 @@
*/
final OptionalBool returnsReceiver;
- final boolean hasMonitorOnReceiver;
- final boolean modifiesInstanceFields;
+ public final boolean hasMonitorOnReceiver;
+ public final boolean modifiesInstanceFields;
public ClassInlinerEligibilityInfo(
List<Pair<Invoke.Type, DexMethod>> callsReceiver,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index 371b79a..32e25f1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -53,6 +53,7 @@
import com.android.tools.r8.ir.optimize.Inliner.Reason;
import com.android.tools.r8.ir.optimize.InliningOracle;
import com.android.tools.r8.ir.optimize.classinliner.ClassInliner.EligibilityStatus;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
import com.android.tools.r8.ir.optimize.info.FieldOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
@@ -1096,33 +1097,22 @@
}
MethodOptimizationInfo optimizationInfo = singleTarget.getDefinition().getOptimizationInfo();
- ClassInlinerEligibilityInfo eligibility = optimizationInfo.getClassInlinerEligibility();
- if (eligibility == null) {
- return false;
- }
-
- if (root.isStaticGet()) {
- // If we are class inlining a singleton instance from a static-get, then we don't know the
- // value of the fields.
- ParameterUsage receiverUsage = optimizationInfo.getParameterUsages(0);
- if (receiverUsage == null || receiverUsage.hasFieldRead) {
+ ClassInlinerMethodConstraint classInlinerMethodConstraint =
+ optimizationInfo.getClassInlinerMethodConstraint();
+ if (root.isNewInstance()) {
+ if (!classInlinerMethodConstraint.isEligibleForNewInstanceClassInlining(singleTarget)) {
return false;
}
- if (eligibility.hasMonitorOnReceiver) {
- // We will not be able to remove the monitor instruction afterwards.
- return false;
- }
- if (eligibility.modifiesInstanceFields) {
- // The static instance could be accessed from elsewhere. Therefore, we cannot
- // allow side-effects to be removed and therefore cannot class inline method
- // calls that modifies the instance.
+ } else {
+ assert root.isStaticGet();
+ if (!classInlinerMethodConstraint.isEligibleForStaticGetClassInlining(singleTarget)) {
return false;
}
}
// If the method returns receiver and the return value is actually
// used in the code we need to make some additional checks.
- if (!eligibilityAcceptanceCheck.test(eligibility)) {
+ if (!eligibilityAcceptanceCheck.test(optimizationInfo.getClassInlinerEligibility())) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
new file mode 100644
index 0000000..c441134
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysFalseClassInlinerMethodConstraint.java
@@ -0,0 +1,29 @@
+// Copyright (c) 2021, 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.classinliner.constraint;
+
+import com.android.tools.r8.graph.ProgramMethod;
+
+public class AlwaysFalseClassInlinerMethodConstraint implements ClassInlinerMethodConstraint {
+
+ private static final AlwaysFalseClassInlinerMethodConstraint INSTANCE =
+ new AlwaysFalseClassInlinerMethodConstraint();
+
+ private AlwaysFalseClassInlinerMethodConstraint() {}
+
+ public static AlwaysFalseClassInlinerMethodConstraint getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public boolean isEligibleForNewInstanceClassInlining(ProgramMethod method) {
+ return false;
+ }
+
+ @Override
+ public boolean isEligibleForStaticGetClassInlining(ProgramMethod method) {
+ return false;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
new file mode 100644
index 0000000..3488111
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/AlwaysTrueClassInlinerMethodConstraint.java
@@ -0,0 +1,29 @@
+// Copyright (c) 2021, 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.classinliner.constraint;
+
+import com.android.tools.r8.graph.ProgramMethod;
+
+public class AlwaysTrueClassInlinerMethodConstraint implements ClassInlinerMethodConstraint {
+
+ private static final AlwaysTrueClassInlinerMethodConstraint INSTANCE =
+ new AlwaysTrueClassInlinerMethodConstraint();
+
+ private AlwaysTrueClassInlinerMethodConstraint() {}
+
+ public static AlwaysTrueClassInlinerMethodConstraint getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public boolean isEligibleForNewInstanceClassInlining(ProgramMethod method) {
+ return true;
+ }
+
+ @Override
+ public boolean isEligibleForStaticGetClassInlining(ProgramMethod method) {
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
new file mode 100644
index 0000000..e8ab3ab
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraint.java
@@ -0,0 +1,14 @@
+// Copyright (c) 2021, 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.classinliner.constraint;
+
+import com.android.tools.r8.graph.ProgramMethod;
+
+public interface ClassInlinerMethodConstraint {
+
+ boolean isEligibleForNewInstanceClassInlining(ProgramMethod method);
+
+ boolean isEligibleForStaticGetClassInlining(ProgramMethod method);
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraintAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraintAnalysis.java
new file mode 100644
index 0000000..fea67a4
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/ClassInlinerMethodConstraintAnalysis.java
@@ -0,0 +1,73 @@
+// Copyright (c) 2021, 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.classinliner.constraint;
+
+import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo;
+import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo;
+import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
+
+public class ClassInlinerMethodConstraintAnalysis {
+
+ public static ClassInlinerMethodConstraint analyze(
+ ClassInlinerEligibilityInfo classInlinerEligibilityInfo,
+ ParameterUsagesInfo parameterUsagesInfo) {
+ boolean isEligibleForNewInstanceClassInlining =
+ isEligibleForNewInstanceClassInlining(classInlinerEligibilityInfo);
+ boolean isEligibleForStaticGetClassInlining =
+ isEligibleForStaticGetClassInlining(classInlinerEligibilityInfo, parameterUsagesInfo);
+ if (isEligibleForNewInstanceClassInlining) {
+ if (isEligibleForStaticGetClassInlining) {
+ return alwaysTrue();
+ }
+ return onlyNewInstanceClassInlining();
+ }
+ assert !isEligibleForStaticGetClassInlining;
+ return alwaysFalse();
+ }
+
+ private static boolean isEligibleForNewInstanceClassInlining(
+ ClassInlinerEligibilityInfo classInlinerEligibilityInfo) {
+ return classInlinerEligibilityInfo != null;
+ }
+
+ private static boolean isEligibleForStaticGetClassInlining(
+ ClassInlinerEligibilityInfo classInlinerEligibilityInfo,
+ ParameterUsagesInfo parameterUsagesInfo) {
+ if (classInlinerEligibilityInfo == null || parameterUsagesInfo == null) {
+ return false;
+ }
+ if (classInlinerEligibilityInfo.hasMonitorOnReceiver) {
+ // We will not be able to remove the monitor instruction afterwards.
+ return false;
+ }
+ if (classInlinerEligibilityInfo.modifiesInstanceFields) {
+ // The static instance could be accessed from elsewhere. Therefore, we cannot allow
+ // side-effects to be removed and therefore cannot class inline method calls that modifies the
+ // instance.
+ return false;
+ }
+ ParameterUsage receiverUsage = parameterUsagesInfo.getParameterUsage(0);
+ if (receiverUsage == null) {
+ return false;
+ }
+ if (receiverUsage.hasFieldRead) {
+ // We don't know the value of the field.
+ return false;
+ }
+ return true;
+ }
+
+ private static AlwaysFalseClassInlinerMethodConstraint alwaysFalse() {
+ return AlwaysFalseClassInlinerMethodConstraint.getInstance();
+ }
+
+ private static AlwaysTrueClassInlinerMethodConstraint alwaysTrue() {
+ return AlwaysTrueClassInlinerMethodConstraint.getInstance();
+ }
+
+ private static OnlyNewInstanceClassInlinerMethodConstraint onlyNewInstanceClassInlining() {
+ return OnlyNewInstanceClassInlinerMethodConstraint.getInstance();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/OnlyNewInstanceClassInlinerMethodConstraint.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/OnlyNewInstanceClassInlinerMethodConstraint.java
new file mode 100644
index 0000000..d3f35d4
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/constraint/OnlyNewInstanceClassInlinerMethodConstraint.java
@@ -0,0 +1,29 @@
+// Copyright (c) 2021, 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.classinliner.constraint;
+
+import com.android.tools.r8.graph.ProgramMethod;
+
+public class OnlyNewInstanceClassInlinerMethodConstraint implements ClassInlinerMethodConstraint {
+
+ private static final OnlyNewInstanceClassInlinerMethodConstraint INSTANCE =
+ new OnlyNewInstanceClassInlinerMethodConstraint();
+
+ private OnlyNewInstanceClassInlinerMethodConstraint() {}
+
+ public static OnlyNewInstanceClassInlinerMethodConstraint getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ public boolean isEligibleForNewInstanceClassInlining(ProgramMethod method) {
+ return true;
+ }
+
+ @Override
+ public boolean isEligibleForStaticGetClassInlining(ProgramMethod method) {
+ return false;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
index a9854ee..45764df 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/DefaultMethodOptimizationInfo.java
@@ -13,6 +13,8 @@
import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.AlwaysFalseClassInlinerMethodConstraint;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.DefaultInstanceInitializerInfo;
@@ -74,6 +76,11 @@
}
@Override
+ public ClassInlinerMethodConstraint getClassInlinerMethodConstraint() {
+ return AlwaysFalseClassInlinerMethodConstraint.getInstance();
+ }
+
+ @Override
public TypeElement getDynamicUpperBoundType() {
return UNKNOWN_TYPE;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
index 93a330e..7cced9d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfo.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
@@ -35,6 +36,8 @@
public abstract boolean classInitializerMayBePostponed();
+ public abstract ClassInlinerMethodConstraint getClassInlinerMethodConstraint();
+
public abstract TypeElement getDynamicUpperBoundType();
public final TypeElement getDynamicUpperBoundTypeOrElse(TypeElement orElse) {
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 7432e43..804b6b3 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
@@ -90,6 +90,8 @@
import com.android.tools.r8.ir.optimize.DynamicTypeOptimization;
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo;
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerReceiverAnalysis;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraintAnalysis;
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsageBuilder;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeAnalyzer;
@@ -143,12 +145,16 @@
Timing timing) {
DexEncodedMethod definition = method.getDefinition();
identifyBridgeInfo(definition, code, feedback, timing);
- identifyClassInlinerEligibility(code, feedback, timing);
- identifyParameterUsages(definition, code, feedback, timing);
+ ClassInlinerEligibilityInfo classInlinerEligibilityInfo =
+ identifyClassInlinerEligibility(code, feedback, timing);
+ ParameterUsagesInfo parameterUsagesInfo =
+ identifyParameterUsages(definition, code, feedback, timing);
analyzeReturns(code, feedback, timing);
if (options.enableInlining) {
identifyInvokeSemanticsForInlining(definition, code, feedback, timing);
}
+ computeClassInlinerMethodConstraint(
+ method, code, feedback, classInlinerEligibilityInfo, parameterUsagesInfo, timing);
computeSimpleInliningConstraint(method, code, feedback, timing);
computeDynamicReturnType(dynamicTypeOptimization, feedback, definition, code, timing);
computeInitializedClassesOnNormalExit(feedback, definition, code, timing);
@@ -167,14 +173,17 @@
timing.end();
}
- private void identifyClassInlinerEligibility(
+ private ClassInlinerEligibilityInfo identifyClassInlinerEligibility(
IRCode code, OptimizationFeedback feedback, Timing timing) {
timing.begin("Identify class inliner eligibility");
- identifyClassInlinerEligibility(code, feedback);
+ ClassInlinerEligibilityInfo classInlinerEligibilityInfo =
+ identifyClassInlinerEligibility(code, feedback);
timing.end();
+ return classInlinerEligibilityInfo;
}
- private void identifyClassInlinerEligibility(IRCode code, OptimizationFeedback feedback) {
+ private ClassInlinerEligibilityInfo identifyClassInlinerEligibility(
+ IRCode code, OptimizationFeedback feedback) {
// Method eligibility is calculated in similar way for regular method
// and for the constructor. To be eligible method should only be using its
// receiver in the following ways:
@@ -193,14 +202,14 @@
boolean instanceInitializer = definition.isInstanceInitializer();
if (definition.isNative()
|| (!definition.isNonAbstractVirtualMethod() && !instanceInitializer)) {
- return;
+ return null;
}
feedback.setClassInlinerEligibility(definition, null); // To allow returns below.
Value receiver = code.getThis();
if (receiver.numberOfPhiUsers() > 0) {
- return;
+ return null;
}
List<Pair<Invoke.Type, DexMethod>> callsReceiver = new ArrayList<>();
@@ -229,17 +238,17 @@
InstancePut instancePutInstruction = insn.asInstancePut();
// Only allow field writes to the receiver.
if (!isReceiverAlias.test(instancePutInstruction.object())) {
- return;
+ return null;
}
// Do not allow the receiver to escape via a field write.
if (isReceiverAlias.test(instancePutInstruction.value())) {
- return;
+ return null;
}
modifiesInstanceFields = true;
}
DexField field = insn.asFieldInstruction().getField();
if (appView.appInfo().resolveField(field).isFailedOrUnknownResolution()) {
- return;
+ return null;
}
break;
}
@@ -257,7 +266,7 @@
break;
}
// We don't support other direct calls yet.
- return;
+ return null;
}
case INVOKE_STATIC:
@@ -265,27 +274,27 @@
InvokeStatic invoke = insn.asInvokeStatic();
DexClassAndMethod singleTarget = invoke.lookupSingleTarget(appView, context);
if (singleTarget == null) {
- return; // Not allowed.
+ return null; // Not allowed.
}
if (singleTarget.getReference() == dexItemFactory.objectsMethods.requireNonNull) {
if (!invoke.hasOutValue() || !invoke.outValue().hasAnyUsers()) {
continue;
}
}
- return;
+ return null;
}
case INVOKE_VIRTUAL:
{
InvokeVirtual invoke = insn.asInvokeVirtual();
if (ListUtils.lastIndexMatching(invoke.arguments(), isReceiverAlias) != 0) {
- return; // Not allowed.
+ return null; // Not allowed.
}
DexMethod invokedMethod = invoke.getInvokedMethod();
DexType returnType = invokedMethod.proto.returnType;
if (returnType.isClassType()
&& appView.appInfo().inSameHierarchy(returnType, context.getHolderType())) {
- return; // Not allowed, could introduce an alias of the receiver.
+ return null; // Not allowed, could introduce an alias of the receiver.
}
callsReceiver.add(new Pair<>(Invoke.Type.VIRTUAL, invokedMethod));
}
@@ -293,34 +302,35 @@
default:
// Other receiver usages make the method not eligible.
- return;
+ return null;
}
}
if (instanceInitializer && !seenSuperInitCall) {
// Call to super constructor not found?
- return;
+ return null;
}
boolean synchronizedVirtualMethod = definition.isSynchronized() && definition.isVirtualMethod();
-
- feedback.setClassInlinerEligibility(
- definition,
+ ClassInlinerEligibilityInfo classInlinerEligibilityInfo =
new ClassInlinerEligibilityInfo(
callsReceiver,
new ClassInlinerReceiverAnalysis(appView, definition, code).computeReturnsReceiver(),
seenMonitor || synchronizedVirtualMethod,
- modifiesInstanceFields));
+ modifiesInstanceFields);
+ feedback.setClassInlinerEligibility(definition, classInlinerEligibilityInfo);
+ return classInlinerEligibilityInfo;
}
- private void identifyParameterUsages(
+ private ParameterUsagesInfo identifyParameterUsages(
DexEncodedMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
timing.begin("Identify parameter usages");
- identifyParameterUsages(method, code, feedback);
+ ParameterUsagesInfo parameterUsagesInfo = identifyParameterUsages(method, code, feedback);
timing.end();
+ return parameterUsagesInfo;
}
- private void identifyParameterUsages(
+ private ParameterUsagesInfo identifyParameterUsages(
DexEncodedMethod method, IRCode code, OptimizationFeedback feedback) {
List<ParameterUsage> usages = new ArrayList<>();
List<Value> values = code.collectArguments();
@@ -331,11 +341,10 @@
usages.add(usage);
}
}
- feedback.setParameterUsages(
- method,
- usages.isEmpty()
- ? DefaultMethodOptimizationInfo.UNKNOWN_PARAMETER_USAGE_INFO
- : new ParameterUsagesInfo(usages));
+ ParameterUsagesInfo parameterUsagesInfo =
+ !usages.isEmpty() ? new ParameterUsagesInfo(usages) : null;
+ feedback.setParameterUsages(method, parameterUsagesInfo);
+ return parameterUsagesInfo;
}
private ParameterUsage collectParameterUsages(int i, Value root) {
@@ -969,6 +978,31 @@
return true;
}
+ private void computeClassInlinerMethodConstraint(
+ ProgramMethod method,
+ IRCode code,
+ OptimizationFeedback feedback,
+ ClassInlinerEligibilityInfo classInlinerEligibilityInfo,
+ ParameterUsagesInfo parameterUsagesInfo,
+ Timing timing) {
+ timing.begin("Compute class inlining constraint");
+ computeClassInlinerMethodConstraint(
+ method, code, feedback, classInlinerEligibilityInfo, parameterUsagesInfo);
+ timing.end();
+ }
+
+ private void computeClassInlinerMethodConstraint(
+ ProgramMethod method,
+ IRCode code,
+ OptimizationFeedback feedback,
+ ClassInlinerEligibilityInfo classInlinerEligibilityInfo,
+ ParameterUsagesInfo parameterUsagesInfo) {
+ ClassInlinerMethodConstraint classInlinerMethodConstraint =
+ ClassInlinerMethodConstraintAnalysis.analyze(
+ classInlinerEligibilityInfo, parameterUsagesInfo);
+ feedback.setClassInlinerMethodConstraint(method, classInlinerMethodConstraint);
+ }
+
private void computeSimpleInliningConstraint(
ProgramMethod method, IRCode code, OptimizationFeedback feedback, Timing timing) {
if (appView.options().enableSimpleInliningConstraints) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index 1236ed6..39f725d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -250,11 +251,18 @@
}
@Override
- public void setBridgeInfo(DexEncodedMethod method, BridgeInfo bridgeInfo) {
+ public synchronized void setBridgeInfo(DexEncodedMethod method, BridgeInfo bridgeInfo) {
getMethodOptimizationInfoForUpdating(method).setBridgeInfo(bridgeInfo);
}
@Override
+ public synchronized void setClassInlinerMethodConstraint(
+ ProgramMethod method, ClassInlinerMethodConstraint classInlinerConstraint) {
+ getMethodOptimizationInfoForUpdating(method)
+ .setClassInlinerMethodConstraint(classInlinerConstraint);
+ }
+
+ @Override
public synchronized void setClassInlinerEligibility(
DexEncodedMethod method, ClassInlinerEligibilityInfo eligibility) {
getMethodOptimizationInfoForUpdating(method).setClassInlinerEligibility(eligibility);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
index 299f7ce..3b46f4e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -113,6 +114,10 @@
public void setBridgeInfo(DexEncodedMethod method, BridgeInfo bridgeInfo) {}
@Override
+ public void setClassInlinerMethodConstraint(
+ ProgramMethod method, ClassInlinerMethodConstraint classInlinerConstraint) {}
+
+ @Override
public void setClassInlinerEligibility(
DexEncodedMethod method, ClassInlinerEligibilityInfo eligibility) {}
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 945d84a..2624486 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
@@ -15,6 +15,7 @@
import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfoCollection;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
@@ -163,6 +164,12 @@
}
@Override
+ public void setClassInlinerMethodConstraint(
+ ProgramMethod method, ClassInlinerMethodConstraint classInlinerConstraint) {
+ // Ignored.
+ }
+
+ @Override
public void setClassInlinerEligibility(
DexEncodedMethod method, ClassInlinerEligibilityInfo eligibility) {
// Ignored.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/ParameterUsagesInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/ParameterUsagesInfo.java
index 921ae28..4389193 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/ParameterUsagesInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/ParameterUsagesInfo.java
@@ -39,7 +39,7 @@
parametersUsages.stream().map(usage -> usage.index).collect(Collectors.toSet()).size();
}
- ParameterUsage getParameterUsage(int index) {
+ public ParameterUsage getParameterUsage(int index) {
for (ParameterUsage usage : parametersUsages) {
if (usage.index == index) {
return usage;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
index a179561..43667c8 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
@@ -16,6 +16,8 @@
import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.ir.code.InvokeDirect;
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.AlwaysFalseClassInlinerMethodConstraint;
+import com.android.tools.r8.ir.optimize.classinliner.constraint.ClassInlinerMethodConstraint;
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
@@ -33,6 +35,8 @@
private int returnedArgument = DefaultMethodOptimizationInfo.UNKNOWN_RETURNED_ARGUMENT;
private AbstractValue abstractReturnValue =
DefaultMethodOptimizationInfo.UNKNOWN_ABSTRACT_RETURN_VALUE;
+ private ClassInlinerMethodConstraint classInlinerConstraint =
+ AlwaysFalseClassInlinerMethodConstraint.getInstance();
private TypeElement returnsObjectWithUpperBoundType = DefaultMethodOptimizationInfo.UNKNOWN_TYPE;
private ClassTypeElement returnsObjectWithLowerBoundType =
DefaultMethodOptimizationInfo.UNKNOWN_CLASS_TYPE;
@@ -239,6 +243,15 @@
}
@Override
+ public ClassInlinerMethodConstraint getClassInlinerMethodConstraint() {
+ return classInlinerConstraint;
+ }
+
+ void setClassInlinerMethodConstraint(ClassInlinerMethodConstraint classInlinerConstraint) {
+ this.classInlinerConstraint = classInlinerConstraint;
+ }
+
+ @Override
public TypeElement getDynamicUpperBoundType() {
return returnsObjectWithUpperBoundType;
}
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index 3a25d00..1587e8a 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.jar;
+import static com.android.tools.r8.repackaging.Repackaging.DefaultRepackagingConfiguration.TEMPORARY_PACKAGE_NAME;
import static com.android.tools.r8.utils.InternalOptions.ASM_VERSION;
import com.android.tools.r8.ByteDataView;
@@ -185,6 +186,7 @@
}
String desc = namingLens.lookupDescriptor(clazz.type).toString();
String name = namingLens.lookupInternalName(clazz.type);
+ assert !name.contains(TEMPORARY_PACKAGE_NAME);
String signature = clazz.getClassSignature().toRenamedString(namingLens, isTypeMissing);
String superName =
clazz.type == options.itemFactory.objectType
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
index 00e689c..d9baf1f 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassInfo.java
@@ -249,7 +249,10 @@
}
// Rewrite super types.
for (KotlinTypeInfo superType : superTypes) {
- superType.rewrite(kmClass::visitSupertype, appView, namingLens);
+ // Ensure the rewritten super type is not this type.
+ if (clazz.getType() != superType.rewriteType(appView.graphLens())) {
+ superType.rewrite(kmClass::visitSupertype, appView, namingLens);
+ }
}
// Rewrite nested classes.
for (KotlinTypeReference nestedClass : nestedClasses) {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
index c80ed32..54b8054 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinClassifierInfo.java
@@ -7,6 +7,8 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.kotlin.Kotlin.ClassClassifiers;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
@@ -48,6 +50,10 @@
abstract void rewrite(KmTypeVisitor visitor, AppView<?> appView, NamingLens namingLens);
+ public DexType rewriteType(GraphLens graphLens) {
+ return null;
+ }
+
public static class KotlinClassClassifierInfo extends KotlinClassifierInfo {
private final KotlinTypeReference type;
@@ -75,6 +81,11 @@
public void trace(DexDefinitionSupplier definitionSupplier) {
type.trace(definitionSupplier);
}
+
+ @Override
+ public DexType rewriteType(GraphLens graphLens) {
+ return type.rewriteType(graphLens);
+ }
}
public static class KotlinTypeParameterClassifierInfo extends KotlinClassifierInfo {
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
index fdb9472..1e3273c 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinMetadataRewriter.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.graph.DexEncodedAnnotation;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.DexValue.DexValueArray;
import com.android.tools.r8.graph.DexValue.DexValueInt;
@@ -79,14 +80,14 @@
this.kotlin = factory.kotlin;
}
- private static boolean isNotKotlinMetadata(AppView<?> appView, DexAnnotation annotation) {
- return annotation.annotation.type != appView.dexItemFactory().kotlinMetadataType;
+ private static boolean isNotKotlinMetadata(DexAnnotation annotation, DexType kotlinMetadataType) {
+ return annotation.annotation.type != kotlinMetadataType;
}
public void runForR8(ExecutorService executorService) throws ExecutionException {
- final DexClass kotlinMetadata =
- appView.definitionFor(appView.dexItemFactory().kotlinMetadataType);
- final WriteMetadataFieldInfo writeMetadataFieldInfo =
+ DexType rewrittenMetadataType = appView.graphLens().lookupClassType(factory.kotlinMetadataType);
+ DexClass kotlinMetadata = appView.definitionFor(rewrittenMetadataType);
+ WriteMetadataFieldInfo writeMetadataFieldInfo =
new WriteMetadataFieldInfo(
kotlinMetadataFieldExists(kotlinMetadata, appView, kotlin.metadata.kind),
kotlinMetadataFieldExists(kotlinMetadata, appView, kotlin.metadata.metadataVersion),
@@ -100,11 +101,13 @@
appView.appInfo().classes(),
clazz -> {
KotlinClassLevelInfo kotlinInfo = clazz.getKotlinInfo();
- DexAnnotation oldMeta = clazz.annotations().getFirstMatching(factory.kotlinMetadataType);
+ DexAnnotation oldMeta = clazz.annotations().getFirstMatching(rewrittenMetadataType);
if (kotlinInfo == INVALID_KOTLIN_INFO) {
// Maintain invalid kotlin info for classes.
return;
}
+ // TODO(b/181103083): Consider removing if rewrittenMetadataType
+ // != factory.kotlinMetadataType
if (oldMeta == null
|| kotlinInfo == NO_KOTLIN_INFO
|| (appView.appInfo().hasLiveness()
@@ -113,7 +116,9 @@
// missing.
if (oldMeta != null) {
clazz.setAnnotations(
- clazz.annotations().keepIf(anno -> isNotKotlinMetadata(appView, anno)));
+ clazz
+ .annotations()
+ .keepIf(anno -> isNotKotlinMetadata(anno, rewrittenMetadataType)));
}
return;
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
index 4e74391..7f068f6 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeInfo.java
@@ -9,6 +9,8 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
import com.android.tools.r8.utils.Reporter;
@@ -120,4 +122,8 @@
flexibleTypeUpperBound.trace(definitionSupplier);
forEachApply(annotations, annotation -> annotation::trace, definitionSupplier);
}
+
+ public DexType rewriteType(GraphLens graphLens) {
+ return classifier.rewriteType(graphLens);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
index 088e7ec..2e1ddf9 100644
--- a/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
+++ b/src/main/java/com/android/tools/r8/kotlin/KotlinTypeReference.java
@@ -7,8 +7,8 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.EnqueuerMetadataTraceable;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -35,6 +35,10 @@
assert unknown != null;
}
+ public DexType getKnown() {
+ return known;
+ }
+
static KotlinTypeReference fromBinaryName(String binaryName, DexItemFactory factory) {
if (DescriptorUtils.isValidBinaryName(binaryName)) {
return fromDescriptor(
@@ -62,18 +66,11 @@
return unknown;
}
assert known != null;
- if (!known.isClassType()) {
- return known.descriptor.toString();
- }
- if (appView.appInfo().hasLiveness()
- && !appView.withLiveness().appInfo().isNonProgramTypeOrLiveProgramType(known)) {
+ DexType rewrittenType = toRewrittenTypeOrNull(appView, known);
+ if (rewrittenType == null) {
return defaultValue;
}
- DexString descriptor = namingLens.lookupDescriptor(known);
- if (descriptor != null) {
- return descriptor.toString();
- }
- return defaultValue;
+ return namingLens.lookupDescriptor(rewrittenType).toString();
}
String toRenamedBinaryNameOrDefault(
@@ -93,6 +90,25 @@
return DescriptorUtils.getBinaryNameFromDescriptor(descriptor);
}
+ private static DexType toRewrittenTypeOrNull(AppView<?> appView, DexType type) {
+ if (type.isArrayType()) {
+ DexType rewrittenBaseType =
+ toRewrittenTypeOrNull(appView, type.toBaseType(appView.dexItemFactory()));
+ return rewrittenBaseType != null
+ ? type.replaceBaseType(rewrittenBaseType, appView.dexItemFactory())
+ : null;
+ }
+ if (!type.isClassType()) {
+ return type;
+ }
+ DexType rewrittenType = appView.graphLens().lookupClassType(type);
+ if (appView.appInfo().hasLiveness()
+ && !appView.withLiveness().appInfo().isNonProgramTypeOrLiveProgramType(rewrittenType)) {
+ return null;
+ }
+ return rewrittenType;
+ }
+
@Override
public String toString() {
return known != null ? known.descriptor.toString() : unknown;
@@ -102,7 +118,14 @@
public void trace(DexDefinitionSupplier definitionSupplier) {
if (known != null && known.isClassType()) {
// Lookup the definition, ignoring the result. This populates the sets in the Enqueuer.
- definitionSupplier.definitionFor(known);
+ definitionSupplier.contextIndependentDefinitionFor(known);
}
}
+
+ public DexType rewriteType(GraphLens graphLens) {
+ if (known != null && known.isClassType()) {
+ return graphLens.lookupClassType(known);
+ }
+ return null;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index 771c336..1b91b62 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -39,8 +39,6 @@
private final ClassNamingStrategy classNamingStrategy;
private final PackageNamingStrategy packageNamingStrategy;
private final Iterable<? extends DexClass> classes;
- private final boolean isAccessModificationAllowed;
- private final Set<String> noObfuscationPrefixes = Sets.newHashSet();
private final Set<String> usedPackagePrefixes = Sets.newHashSet();
private final Set<String> usedTypeNames = Sets.newHashSet();
private final Map<DexType, DexString> renaming = Maps.newIdentityHashMap();
@@ -50,6 +48,7 @@
private final Namespace topLevelState;
private final boolean allowMixedCaseNaming;
private final Predicate<String> isUsed;
+ private final ProguardPackageNameList keepPackageNames;
ClassNameMinifier(
AppView<AppInfoWithLiveness> appView,
@@ -61,8 +60,6 @@
this.packageNamingStrategy = packageNamingStrategy;
this.classes = classes;
InternalOptions options = appView.options();
- this.isAccessModificationAllowed =
- options.getProguardConfiguration().isAccessModificationAllowed();
this.keepInnerClassStructure = options.keepInnerClassStructure();
// Initialize top-level naming state.
@@ -70,9 +67,8 @@
String newPackageDescriptor =
StringUtils.replaceAll(options.getProguardConfiguration().getPackagePrefix(), ".", "/");
if (!newPackageDescriptor.isEmpty()) {
- registerPackagePrefixesAsUsed(newPackageDescriptor, false);
+ registerPackagePrefixesAsUsed(newPackageDescriptor);
}
-
states.put("", topLevelState);
if (options.getProguardConfiguration().hasDontUseMixedCaseClassnames()) {
@@ -82,6 +78,7 @@
allowMixedCaseNaming = true;
isUsed = usedTypeNames::contains;
}
+ keepPackageNames = options.getProguardConfiguration().getKeepPackageNamesPatterns();
}
private void setUsedTypeName(String typeName) {
@@ -180,8 +177,7 @@
private void registerClassAsUsed(DexType type, DexString descriptor) {
renaming.put(type, descriptor);
registerPackagePrefixesAsUsed(
- getParentPackagePrefix(getClassBinaryNameFromDescriptor(descriptor.toSourceString())),
- isAccessModificationAllowed);
+ getParentPackagePrefix(getClassBinaryNameFromDescriptor(descriptor.toSourceString())));
setUsedTypeName(descriptor.toString());
if (keepInnerClassStructure) {
DexType outerClass = getOutClassForType(type);
@@ -197,15 +193,11 @@
}
/** Registers the given package prefix and all of parent packages as used. */
- private void registerPackagePrefixesAsUsed(String packagePrefix, boolean isMinificationAllowed) {
- // If -allowaccessmodification is not set, we may keep classes in their original packages,
- // accounting for package-private accesses.
- if (!isMinificationAllowed) {
- noObfuscationPrefixes.add(packagePrefix);
- }
+ private void registerPackagePrefixesAsUsed(String packagePrefix) {
String usedPrefix = packagePrefix;
while (usedPrefix.length() > 0) {
usedPackagePrefixes.add(usedPrefix);
+ states.computeIfAbsent(usedPrefix, Namespace::new);
usedPrefix = getParentPackagePrefix(usedPrefix);
}
}
@@ -259,9 +251,7 @@
String packageName = getPackageBinaryNameFromJavaType(type.getPackageDescriptor());
// Check whether the given class should be kept.
// or check whether the given class belongs to a package that is kept for another class.
- ProguardPackageNameList keepPackageNames =
- appView.options().getProguardConfiguration().getKeepPackageNamesPatterns();
- if (noObfuscationPrefixes.contains(packageName) || keepPackageNames.matches(type)) {
+ if (keepPackageNames.matches(type)) {
return states.computeIfAbsent(packageName, Namespace::new);
}
return getStateForPackagePrefix(packageName);
@@ -272,15 +262,9 @@
if (state == null) {
// Calculate the parent package prefix, e.g., La/b/c -> La/b
String parentPackage = getParentPackagePrefix(prefix);
- Namespace superState;
- if (noObfuscationPrefixes.contains(parentPackage)) {
- // Restore a state for parent package prefix if it should be kept.
- superState = states.computeIfAbsent(parentPackage, Namespace::new);
- } else {
- // Create a state for parent package prefix, if necessary, in a recursive manner.
- // That recursion should end when the parent package hits the top-level, "".
- superState = getStateForPackagePrefix(parentPackage);
- }
+ // Create a state for parent package prefix, if necessary, in a recursive manner.
+ // That recursion should end when the parent package hits the top-level, "".
+ Namespace superState = getStateForPackagePrefix(parentPackage);
// From the super state, get a renamed package prefix for the current level.
String renamedPackagePrefix = superState.nextPackagePrefix();
// Create a new state, which corresponds to a new name space, for the current level.
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
index eba0a87..cdfa649 100644
--- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
+++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -9,6 +9,7 @@
import static com.android.tools.r8.utils.DescriptorUtils.INNER_CLASS_SEPARATOR;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedMember;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
@@ -26,6 +27,7 @@
import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.synthesis.CommittedItems;
import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions.PackageObfuscationMode;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
@@ -291,26 +293,46 @@
public static class DefaultRepackagingConfiguration implements RepackagingConfiguration {
+ private final AppView<?> appView;
private final DexItemFactory dexItemFactory;
private final ProguardConfiguration proguardConfiguration;
+ public static final String TEMPORARY_PACKAGE_NAME = "TEMPORARY_PACKAGE_NAME_FOR_";
- public DefaultRepackagingConfiguration(
- DexItemFactory dexItemFactory, ProguardConfiguration proguardConfiguration) {
- this.dexItemFactory = dexItemFactory;
- this.proguardConfiguration = proguardConfiguration;
+ public DefaultRepackagingConfiguration(AppView<?> appView) {
+ this.appView = appView;
+ this.dexItemFactory = appView.dexItemFactory();
+ this.proguardConfiguration = appView.options().getProguardConfiguration();
}
@Override
public String getNewPackageDescriptor(ProgramPackage pkg, Set<String> seenPackageDescriptors) {
String newPackageDescriptor =
DescriptorUtils.getBinaryNameFromJavaType(proguardConfiguration.getPackagePrefix());
- if (proguardConfiguration.getPackageObfuscationMode().isRepackageClasses()) {
+ PackageObfuscationMode packageObfuscationMode =
+ proguardConfiguration.getPackageObfuscationMode();
+ if (packageObfuscationMode.isRepackageClasses()) {
return newPackageDescriptor;
}
+ assert packageObfuscationMode.isFlattenPackageHierarchy()
+ || packageObfuscationMode.isMinification();
if (!newPackageDescriptor.isEmpty()) {
newPackageDescriptor += DESCRIPTOR_PACKAGE_SEPARATOR;
}
- newPackageDescriptor += pkg.getLastPackageName();
+ if (packageObfuscationMode.isMinification()) {
+ assert !proguardConfiguration.hasApplyMappingFile();
+ // Always keep top-level classes since there packages can never be minified.
+ if (pkg.getPackageDescriptor().equals("")
+ || proguardConfiguration.getKeepPackageNamesPatterns().matches(pkg)
+ || mayHavePinnedPackagePrivateOrProtectedItem(pkg)) {
+ return pkg.getPackageDescriptor();
+ }
+ // For us to rename shaking/A to a/a if we have a class shaking/Kept, we have to propose
+ // a different name than the last package name - the class will be minified in
+ // ClassNameMinifier.
+ newPackageDescriptor += TEMPORARY_PACKAGE_NAME + pkg.getLastPackageName();
+ } else {
+ newPackageDescriptor += pkg.getLastPackageName();
+ }
String finalPackageDescriptor = newPackageDescriptor;
for (int i = 1; seenPackageDescriptors.contains(finalPackageDescriptor); i++) {
finalPackageDescriptor = newPackageDescriptor + INNER_CLASS_SEPARATOR + i;
@@ -318,6 +340,24 @@
return finalPackageDescriptor;
}
+ private boolean mayHavePinnedPackagePrivateOrProtectedItem(ProgramPackage pkg) {
+ // Go through all package classes and members to see if there is a pinned package-private
+ // item, in which case we cannot move it because there may be a reflective access to it.
+ for (DexProgramClass clazz : pkg.classesInPackage()) {
+ if (clazz.getAccessFlags().isPackagePrivateOrProtected()
+ && appView.getKeepInfo().getClassInfo(clazz).isPinned()) {
+ return true;
+ }
+ for (DexEncodedMember<?, ?> member : clazz.members()) {
+ if (member.getAccessFlags().isPackagePrivateOrProtected()
+ && appView.getKeepInfo().getMemberInfo(member, clazz).isPinned()) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
@Override
public DexType getRepackagedType(
DexProgramClass clazz,
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index 0b02310..813ae66 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -160,14 +160,6 @@
this.isVerbose = isVerbose;
}
- public static <T, ST extends StackTraceElementProxy<T, ST>> Retrace<T, ST> createRetrace(
- StackTraceLineParser<T, ST> stackTraceLineParser,
- StackTraceElementProxyRetracer<T, ST> proxyRetracer,
- DiagnosticsHandler diagnosticsHandler,
- boolean isVerbose) {
- return new Retrace<>(stackTraceLineParser, proxyRetracer, diagnosticsHandler, isVerbose);
- }
-
/**
* Retraces a stack frame and calls the consumer for each retraced line
*
diff --git a/src/main/java/com/android/tools/r8/retrace/StringRetrace.java b/src/main/java/com/android/tools/r8/retrace/StringRetrace.java
index 957e357..825ac52 100644
--- a/src/main/java/com/android/tools/r8/retrace/StringRetrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/StringRetrace.java
@@ -47,7 +47,7 @@
}
/**
- * Retraces a list of stack-traces strings and returns a list. Ambiguous and inline frames will be
+ * Retraces a list of stack-trace lines and returns a list. Ambiguous and inline frames will be
* appended automatically to the retraced string.
*
* @param stackTrace the incoming stack trace
diff --git a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
index 762617e..057a80f 100644
--- a/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
+++ b/src/main/java/com/android/tools/r8/shaking/AnnotationRemover.java
@@ -115,10 +115,6 @@
return isAnnotationTypeLive;
case DexAnnotation.VISIBILITY_BUILD:
- if (DexAnnotation.isSynthesizedClassMapAnnotation(annotation, dexItemFactory)) {
- // TODO(sgjesse) When should these be removed?
- return true;
- }
if (!config.runtimeInvisibleAnnotations) {
return false;
}
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 da98174..81239aa 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepInfoCollection.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexDefinitionSupplier;
import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMember;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
@@ -72,6 +73,14 @@
*/
public abstract KeepFieldInfo getFieldInfo(DexEncodedField field, DexProgramClass holder);
+ public KeepMemberInfo<?, ?> getMemberInfo(DexEncodedMember<?, ?> member, DexProgramClass holder) {
+ if (member.isDexEncodedField()) {
+ return getFieldInfo(member.asDexEncodedField(), holder);
+ }
+ assert member.isDexEncodedMethod();
+ return getMethodInfo(member.asDexEncodedMethod(), holder);
+ }
+
public final KeepClassInfo getClassInfo(DexType type, DexDefinitionSupplier definitions) {
DexProgramClass clazz = asProgramClassOrNull(definitions.definitionFor(type));
return clazz == null ? keepInfoForNonProgramClass() : getClassInfo(clazz);
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java b/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
index 58315d4..a60967f 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexInfo.java
@@ -91,6 +91,11 @@
return this == NONE;
}
+ public boolean isMainDexTypeThatShouldIncludeDependencies(DexType type) {
+ // Dependencies of 'type' are only needed if 'type' is a direct/executed main-dex type.
+ return classList.contains(type) || tracedRoots.contains(type);
+ }
+
public boolean isMainDex(ProgramDefinition definition) {
return isFromList(definition) || isTracedRoot(definition) || isDependency(definition);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
index 3632f93..2cce6ff 100644
--- a/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
+++ b/src/main/java/com/android/tools/r8/shaking/MissingClasses.java
@@ -264,9 +264,9 @@
dexItemFactory.annotationMethodParameters,
dexItemFactory.annotationSourceDebugExtension,
dexItemFactory.annotationSynthesizedClass,
- dexItemFactory.annotationSynthesizedClassMap,
dexItemFactory.annotationThrows,
- dexItemFactory.serializedLambdaType)
+ dexItemFactory.serializedLambdaType,
+ dexItemFactory.unsafeType)
.addAll(dexItemFactory.getJavaConversionTypes())
.addAll(dexItemFactory.getJ$ConversionTypes())
.build();
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
index 8fdd330..6d3a8ca 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java
@@ -397,6 +397,12 @@
synthesizeKeepRulesForRecompilation();
}
+ if (packageObfuscationMode == PackageObfuscationMode.NONE
+ && obfuscating
+ && !hasApplyMappingFile()) {
+ packageObfuscationMode = PackageObfuscationMode.MINIFICATION;
+ }
+
return buildRaw();
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardPackageMatcher.java b/src/main/java/com/android/tools/r8/shaking/ProguardPackageMatcher.java
index 48c4703..f31087d 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardPackageMatcher.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardPackageMatcher.java
@@ -4,8 +4,6 @@
package com.android.tools.r8.shaking;
-import com.android.tools.r8.graph.DexType;
-
public class ProguardPackageMatcher {
private final String pattern;
@@ -13,8 +11,8 @@
this.pattern = pattern;
}
- public boolean matches(DexType type) {
- return matchPackageNameImpl(pattern, 0, type.getPackageName(), 0);
+ public boolean matches(String packageName) {
+ return matchPackageNameImpl(pattern, 0, packageName, 0);
}
private static boolean matchPackageNameImpl(
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardPackageNameList.java b/src/main/java/com/android/tools/r8/shaking/ProguardPackageNameList.java
index 6d45459..6dcd07b 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardPackageNameList.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardPackageNameList.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.shaking;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramPackage;
import it.unimi.dsi.fastutil.objects.Object2BooleanArrayMap;
import it.unimi.dsi.fastutil.objects.Object2BooleanMap;
import it.unimi.dsi.fastutil.objects.ObjectIterator;
@@ -56,9 +57,17 @@
}
public boolean matches(DexType type) {
+ return matches(type.getPackageName());
+ }
+
+ public boolean matches(ProgramPackage pkg) {
+ return matches(pkg.getPackageName());
+ }
+
+ private boolean matches(String pkgName) {
for (Object2BooleanMap.Entry<ProguardPackageMatcher> packageName :
packageNames.object2BooleanEntrySet()) {
- if (packageName.getKey().matches(type)) {
+ if (packageName.getKey().matches(pkgName)) {
// If we match a negation, abort as non-match. If we match a positive, return true.
return !packageName.getBooleanValue();
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
index 82f3204..bff9202 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
@@ -15,7 +15,6 @@
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.MainDexInfo;
import java.util.Comparator;
-import java.util.Set;
/**
* A synthesizing context is a description of the context that gives rise to a synthetic item.
@@ -123,14 +122,15 @@
appView.rewritePrefix.rewriteType(hygienicType, rewrittenType);
}
+ // TODO(b/180074885): Remove this once main-dex is traced at the end of of compilation.
void addIfDerivedFromMainDexClass(
- DexProgramClass externalSyntheticClass,
- MainDexInfo mainDexInfo,
- Set<DexType> allMainDexTypes) {
+ DexProgramClass externalSyntheticClass, MainDexInfo mainDexInfo) {
+ if (mainDexInfo.isMainDex(externalSyntheticClass)) {
+ return;
+ }
// The input context type (not the annotated context) determines if the derived class is to be
- // in main dex.
- // TODO(b/168584485): Once resolved allMainDexTypes == mainDexClasses.
- if (allMainDexTypes.contains(inputContextType)) {
+ // in main dex, as it is the input context type that is traced as part of main-dex tracing.
+ if (mainDexInfo.isMainDexTypeThatShouldIncludeDependencies(inputContextType)) {
mainDexInfo.addSyntheticClass(externalSyntheticClass);
}
}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
index 65de13f..2e70db6 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -7,7 +7,6 @@
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -32,11 +31,9 @@
import com.android.tools.r8.utils.collections.BidirectionalManyToOneRepresentativeMap;
import com.android.tools.r8.utils.collections.BidirectionalOneToOneHashMap;
import com.android.tools.r8.utils.structural.RepresentativeMap;
-import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
-import com.google.common.collect.ListMultimap;
import com.google.common.collect.Sets;
import com.google.common.hash.HashCode;
import java.util.ArrayList;
@@ -48,7 +45,6 @@
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import java.util.TreeSet;
import java.util.function.BiConsumer;
import java.util.function.Function;
@@ -262,7 +258,6 @@
Result computeFinalSynthetics(AppView<?> appView) {
assert verifyNoNestedSynthetics();
DexApplication application;
- MainDexInfo mainDexInfo = appView.appInfo().getMainDexInfo();
Builder lensBuilder = new Builder();
ImmutableMap.Builder<DexType, SyntheticMethodReference> finalMethodsBuilder =
ImmutableMap.builder();
@@ -290,11 +285,6 @@
ImmutableMap<DexType, SyntheticProgramClassReference> finalClasses =
finalClassesBuilder.build();
- handleSynthesizedClassMapping(
- finalSyntheticProgramDefinitions, application, options, mainDexInfo, lensBuilder.typeMap);
-
- assert appView.appInfo().getMainDexInfo() == mainDexInfo;
-
Set<DexType> prunedSynthetics = Sets.newIdentityHashSet();
committed.forEachNonLegacyItem(
reference -> {
@@ -354,96 +344,6 @@
return true;
}
- private void handleSynthesizedClassMapping(
- List<DexProgramClass> finalSyntheticClasses,
- DexApplication application,
- InternalOptions options,
- MainDexInfo mainDexInfo,
- Map<DexType, DexType> derivedMainDexTypesToIgnore) {
- boolean includeSynthesizedClassMappingInOutput = shouldAnnotateSynthetics(options);
- if (includeSynthesizedClassMappingInOutput) {
- updateSynthesizedClassMapping(application, finalSyntheticClasses);
- }
- updateMainDexListWithSynthesizedClassMap(application, mainDexInfo, derivedMainDexTypesToIgnore);
- if (!includeSynthesizedClassMappingInOutput) {
- clearSynthesizedClassMapping(application);
- }
- }
-
- private void updateSynthesizedClassMapping(
- DexApplication application, List<DexProgramClass> finalSyntheticClasses) {
- ListMultimap<DexProgramClass, DexProgramClass> originalToSynthesized =
- ArrayListMultimap.create();
- for (DexType type : committed.getLegacyTypes()) {
- DexProgramClass clazz = DexProgramClass.asProgramClassOrNull(application.definitionFor(type));
- if (clazz != null) {
- for (DexProgramClass origin : clazz.getSynthesizedFrom()) {
- originalToSynthesized.put(origin, clazz);
- }
- }
- }
- for (DexProgramClass clazz : finalSyntheticClasses) {
- for (DexProgramClass origin : clazz.getSynthesizedFrom()) {
- originalToSynthesized.put(origin, clazz);
- }
- }
- for (Map.Entry<DexProgramClass, Collection<DexProgramClass>> entry :
- originalToSynthesized.asMap().entrySet()) {
- DexProgramClass original = entry.getKey();
- // Use a tree set to make sure that we have an ordering on the types.
- // These types are put in an array in annotations in the output and we
- // need a consistent ordering on them.
- TreeSet<DexType> synthesized = new TreeSet<>(DexType::compareTo);
- entry.getValue().stream()
- .map(dexProgramClass -> dexProgramClass.type)
- .forEach(synthesized::add);
- synthesized.addAll(
- DexAnnotation.readAnnotationSynthesizedClassMap(original, application.dexItemFactory));
-
- DexAnnotation updatedAnnotation =
- DexAnnotation.createAnnotationSynthesizedClassMap(
- synthesized, application.dexItemFactory);
-
- original.setAnnotations(original.annotations().getWithAddedOrReplaced(updatedAnnotation));
- }
- }
-
- private void updateMainDexListWithSynthesizedClassMap(
- DexApplication application,
- MainDexInfo mainDexInfo,
- Map<DexType, DexType> derivedMainDexTypesToIgnore) {
- if (mainDexInfo.isEmpty()) {
- return;
- }
- List<DexProgramClass> newMainDexClasses = new ArrayList<>();
- mainDexInfo.forEachExcludingDependencies(
- dexType -> {
- DexProgramClass programClass =
- DexProgramClass.asProgramClassOrNull(application.definitionFor(dexType));
- if (programClass != null) {
- Collection<DexType> derived =
- DexAnnotation.readAnnotationSynthesizedClassMap(
- programClass, application.dexItemFactory);
- for (DexType type : derived) {
- DexType mappedType = derivedMainDexTypesToIgnore.getOrDefault(type, type);
- DexProgramClass syntheticClass =
- DexProgramClass.asProgramClassOrNull(application.definitionFor(mappedType));
- if (syntheticClass != null) {
- newMainDexClasses.add(syntheticClass);
- }
- }
- }
- });
- newMainDexClasses.forEach(mainDexInfo::addSyntheticClass);
- }
-
- private void clearSynthesizedClassMapping(DexApplication application) {
- for (DexProgramClass clazz : application.classes()) {
- clazz.setAnnotations(
- clazz.annotations().getWithout(application.dexItemFactory.annotationSynthesizedClassMap));
- }
- }
-
private static DexApplication buildLensAndProgram(
AppView<?> appView,
Map<DexType, EquivalenceGroup<SyntheticMethodDefinition>> syntheticMethodGroups,
@@ -454,23 +354,8 @@
DexApplication application = appView.appInfo().app();
DexItemFactory factory = appView.dexItemFactory();
List<DexProgramClass> newProgramClasses = new ArrayList<>();
-
- // TODO(b/168584485): Remove this once class-mapping support is removed.
- Set<DexType> derivedMainDexTypes = Sets.newIdentityHashSet();
- MainDexInfo mainDexInfo = appView.appInfo().getMainDexInfo();
- mainDexInfo.forEachExcludingDependencies(
- mainDexType -> {
- derivedMainDexTypes.add(mainDexType);
- DexProgramClass mainDexClass =
- DexProgramClass.asProgramClassOrNull(
- appView.appInfo().definitionForWithoutExistenceAssert(mainDexType));
- if (mainDexClass != null) {
- derivedMainDexTypes.addAll(
- DexAnnotation.readAnnotationSynthesizedClassMap(mainDexClass, factory));
- }
- });
-
Set<DexType> pruned = Sets.newIdentityHashSet();
+
syntheticMethodGroups.forEach(
(syntheticType, syntheticGroup) -> {
SyntheticMethodDefinition representative = syntheticGroup.getRepresentative();
@@ -571,8 +456,7 @@
addMainDexAndSynthesizedFromForMember(
member,
externalSyntheticClass,
- mainDexInfo,
- derivedMainDexTypes,
+ appView.appInfo().getMainDexInfo(),
appForLookup::programDefinitionFor);
}
});
@@ -593,8 +477,7 @@
addMainDexAndSynthesizedFromForMember(
member,
externalSyntheticClass,
- mainDexInfo,
- derivedMainDexTypes,
+ appView.appInfo().getMainDexInfo(),
appForLookup::programDefinitionFor);
}
});
@@ -644,11 +527,8 @@
SyntheticDefinition<?, ?, ?> member,
DexProgramClass externalSyntheticClass,
MainDexInfo mainDexInfo,
- Set<DexType> derivedMainDexTypes,
Function<DexType, DexProgramClass> definitions) {
- member
- .getContext()
- .addIfDerivedFromMainDexClass(externalSyntheticClass, mainDexInfo, derivedMainDexTypes);
+ member.getContext().addIfDerivedFromMainDexClass(externalSyntheticClass, mainDexInfo);
// TODO(b/168584485): Remove this once class-mapping support is removed.
DexProgramClass from = definitions.apply(member.getContext().getSynthesizingContextType());
if (from != null) {
@@ -661,7 +541,6 @@
// This is currently also disabled on CF to CF desugaring to avoid missing class references to
// the annotated classes.
// TODO(b/147485959): Find an alternative encoding for synthetics to avoid missing-class refs.
- // TODO(b/168584485): Remove support for main-dex tracing with the class-map annotation.
return options.intermediate && !options.cfToCfDesugar;
}
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
index 6e501fc..7181e84 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApiLevel.java
@@ -39,7 +39,8 @@
O_MR1(27),
P(28),
Q(29),
- R(30);
+ R(30),
+ S(31);
public static final AndroidApiLevel LATEST = R;
diff --git a/src/main/java/com/android/tools/r8/utils/DexUtils.java b/src/main/java/com/android/tools/r8/utils/DexUtils.java
new file mode 100644
index 0000000..265a130
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/DexUtils.java
@@ -0,0 +1,13 @@
+// Copyright (c) 2021, 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;
+
+public class DexUtils {
+ public static String getDefaultDexFileName(int fileIndex) {
+ return fileIndex == 0
+ ? "classes" + FileUtils.DEX_EXTENSION
+ : ("classes" + (fileIndex + 1) + FileUtils.DEX_EXTENSION);
+ }
+}
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 4e787b6..ea310aa 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1046,8 +1046,11 @@
}
public enum PackageObfuscationMode {
- // General package obfuscation.
+ // No package obfuscation.
NONE,
+ // Strategy based on ordinary package obfuscation when no package-obfuscation mode is specified
+ // by the users. In practice this falls back to FLATTEN but with keeping package-names.
+ MINIFICATION,
// Repackaging all classes into the single user-given (or top-level) package.
REPACKAGE,
// Repackaging all packages into the single user-given (or top-level) package.
@@ -1065,6 +1068,10 @@
return this == REPACKAGE;
}
+ public boolean isMinification() {
+ return this == MINIFICATION;
+ }
+
public boolean isSome() {
return !isNone();
}
@@ -1242,10 +1249,7 @@
public Consumer<String> processingContextsConsumer = null;
public Function<AppView<AppInfoWithLiveness>, RepackagingConfiguration>
- repackagingConfigurationFactory =
- appView ->
- new DefaultRepackagingConfiguration(
- appView.dexItemFactory(), appView.options().getProguardConfiguration());
+ repackagingConfigurationFactory = DefaultRepackagingConfiguration::new;
public BiConsumer<DexItemFactory, HorizontallyMergedClasses> horizontallyMergedClassesConsumer =
ConsumerUtils.emptyBiConsumer();
diff --git a/src/test/examples/naming101/c.java b/src/test/examples/naming101/c.java
index 21744bc..7477024 100644
--- a/src/test/examples/naming101/c.java
+++ b/src/test/examples/naming101/c.java
@@ -4,5 +4,5 @@
package naming101;
public class c {
- public static int i = 1;
+ static int i = 1;
}
diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
index 82cfebf..43bbd99 100644
--- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java
@@ -361,15 +361,25 @@
abstract D8IncrementalTestRunner test(String testName, String packageName, String mainClass);
@Override
- protected void testIntermediateWithMainDexList(String packageName, Path input,
- int expectedMainDexListSize, String... mainDexClasses) throws Throwable {
+ protected void testIntermediateWithMainDexList(
+ String packageName,
+ Path input,
+ int expectedMainDexListSize,
+ List<String> mainDexClasses,
+ List<String> mainDexOverApproximation)
+ throws Throwable {
// Skip those tests.
Assume.assumeTrue(false);
}
@Override
- protected Path buildDexThroughIntermediate(String packageName, Path input, OutputMode outputMode,
- AndroidApiLevel minApi, String... mainDexClasses) throws Throwable {
+ protected Path buildDexThroughIntermediate(
+ String packageName,
+ Path input,
+ OutputMode outputMode,
+ AndroidApiLevel minApi,
+ List<String> mainDexClasses)
+ throws Throwable {
// tests using this should already been skipped.
throw new Unreachable();
}
diff --git a/src/test/java/com/android/tools/r8/D8TestBuilder.java b/src/test/java/com/android/tools/r8/D8TestBuilder.java
index 4c88d91..4913bc5 100644
--- a/src/test/java/com/android/tools/r8/D8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/D8TestBuilder.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.D8Command.Builder;
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase.KeepRuleConsumer;
+import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
@@ -86,4 +87,16 @@
builder.addMainDexRulesFiles(mainDexRuleFiles);
return self();
}
+
+ public D8TestBuilder addMainDexRules(String... rules) {
+ builder.addMainDexRules(Arrays.asList(rules), Origin.unknown());
+ return self();
+ }
+
+ public D8TestBuilder addMainDexKeepClassRules(Class<?>... classes) {
+ for (Class<?> clazz : classes) {
+ addMainDexRules("-keep class " + clazz.getTypeName());
+ }
+ return self();
+ }
}
diff --git a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
index 2d21521..118f3b1 100644
--- a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
+++ b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java
@@ -1780,6 +1780,7 @@
anyDexVm())
.put("lang.Thread.getState.Thread_getState_A01", anyDexVm())
.put("lang.Thread.join.Thread_join_A01", anyDexVm())
+ .put("lang.ThreadGroup.destroy.ThreadGroup_destroy_A01", match(JAVA_RUNTIME))
.put(
"util.concurrent.ScheduledThreadPoolExecutor.getTaskCount.ScheduledThreadPoolExecutor_getTaskCount_A01",
any())
diff --git a/src/test/java/com/android/tools/r8/KotlinTestBase.java b/src/test/java/com/android/tools/r8/KotlinTestBase.java
index 37f4222..1696327 100644
--- a/src/test/java/com/android/tools/r8/KotlinTestBase.java
+++ b/src/test/java/com/android/tools/r8/KotlinTestBase.java
@@ -24,6 +24,7 @@
import java.util.function.Consumer;
import java.util.stream.Collectors;
import org.hamcrest.Matcher;
+import org.junit.rules.TemporaryFolder;
public abstract class KotlinTestBase extends TestBase {
@@ -107,6 +108,11 @@
}
public static KotlinCompileMemoizer getCompileMemoizer(
+ Collection<Path> sources, CfRuntime runtime, TemporaryFolder temporaryFolder) {
+ return new KotlinCompileMemoizer(sources, runtime, temporaryFolder);
+ }
+
+ public static KotlinCompileMemoizer getCompileMemoizer(
Collection<Path> sources, String sharedFolder) {
return compileMemoizers.computeIfAbsent(
sharedFolder, ignore -> new KotlinCompileMemoizer(sources));
@@ -131,12 +137,22 @@
public static class KotlinCompileMemoizer {
private final Collection<Path> sources;
+ private final CfRuntime runtime;
+ private final TemporaryFolder temporaryFolder;
+
private Consumer<KotlinCompilerTool> kotlinCompilerToolConsumer = x -> {};
private final Map<KotlinCompiler, Map<KotlinTargetVersion, Path>> compiledPaths =
new IdentityHashMap<>();
public KotlinCompileMemoizer(Collection<Path> sources) {
+ this(sources, CfRuntime.getCheckedInJdk9(), null);
+ }
+
+ public KotlinCompileMemoizer(
+ Collection<Path> sources, CfRuntime runtime, TemporaryFolder temporaryFolder) {
this.sources = sources;
+ this.runtime = runtime;
+ this.temporaryFolder = temporaryFolder;
}
public KotlinCompileMemoizer configure(Consumer<KotlinCompilerTool> consumer) {
@@ -159,10 +175,11 @@
targetVersion,
ignored -> {
try {
- return kotlinc(compiler, targetVersion)
- .addSourceFiles(sources)
- .apply(kotlinCompilerToolConsumer)
- .compile();
+ KotlinCompilerTool kotlinc =
+ temporaryFolder == null
+ ? kotlinc(compiler, targetVersion)
+ : kotlinc(runtime, temporaryFolder, compiler, targetVersion);
+ return kotlinc.addSourceFiles(sources).apply(kotlinCompilerToolConsumer).compile();
} catch (IOException e) {
throw new RuntimeException(e);
}
diff --git a/src/test/java/com/android/tools/r8/R8RunExamplesKotlinTest.java b/src/test/java/com/android/tools/r8/R8RunExamplesKotlinTest.java
deleted file mode 100644
index 74dfeb4..0000000
--- a/src/test/java/com/android/tools/r8/R8RunExamplesKotlinTest.java
+++ /dev/null
@@ -1,110 +0,0 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8;
-
-import com.android.tools.r8.KotlinCompilerTool.KotlinCompiler;
-import com.android.tools.r8.R8Command.Builder;
-import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
-import com.android.tools.r8.utils.InternalOptions;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import org.junit.runner.RunWith;
-import org.junit.runners.Parameterized;
-import org.junit.runners.Parameterized.Parameters;
-
-@RunWith(Parameterized.class)
-public class R8RunExamplesKotlinTest extends R8RunExamplesCommon {
-
- @Override
- protected void configure(InternalOptions options) {
- super.configure(options);
- }
-
- @Parameters(name = "{0}_{1}_{2}_{3}_{5}_{6}")
- public static Collection<String[]> data() {
- String[] tests = {
- "loops.LoopKt"
- };
-
- List<String[]> fullTestList = new ArrayList<>(tests.length * 2);
- for (String test : tests) {
- fullTestList.add(
- makeTest(Input.JAVAC, CompilerUnderTest.D8, CompilationMode.DEBUG, test, Output.DEX));
- fullTestList.add(
- makeTest(Input.JAVAC, CompilerUnderTest.D8, CompilationMode.RELEASE, test, Output.DEX));
- fullTestList.add(makeTest(Input.DX, CompilerUnderTest.R8, CompilationMode.DEBUG, test));
- fullTestList.add(makeTest(Input.DX, CompilerUnderTest.R8, CompilationMode.RELEASE, test));
- fullTestList.add(
- makeTest(Input.JAVAC, CompilerUnderTest.R8, CompilationMode.DEBUG, test, Output.CF));
- fullTestList.add(
- makeTest(Input.JAVAC, CompilerUnderTest.R8, CompilationMode.RELEASE, test, Output.CF));
- }
- return fullTestList;
- }
-
- @Override
- public Builder addInputFile(Builder builder) {
- return super.addInputFile(builder)
- .addProgramFiles(ToolHelper.getKotlinAnnotationJar(KotlinCompiler.latest()));
- }
-
- @Override
- protected String getExampleDir() {
- return ToolHelper.EXAMPLES_KOTLIN_BUILD_DIR;
- }
-
- @Override
- protected Map<String, TestCondition> getFailingRun() {
- return Collections.emptyMap();
- }
-
- @Override
- protected Map<String, TestCondition> getFailingRunCf() {
- return Collections.emptyMap();
- }
-
- @Override
- protected Set<String> getFailingCompileCfToDex() {
- return Collections.emptySet();
- }
-
- @Override
- protected Set<String> getFailingRunCfToDex() {
- return Collections.emptySet();
- }
-
- @Override
- protected Set<String> getFailingCompileCf() {
- return Collections.emptySet();
- }
-
- @Override
- protected Set<String> getFailingOutputCf() {
- return Collections.emptySet();
- }
-
- @Override
- protected Map<String, TestCondition> getOutputNotIdenticalToJVMOutput() {
- return Collections.emptyMap();
- }
-
- @Override
- protected Map<String, TestCondition> getSkip() {
- return Collections.emptyMap();
- }
-
- public R8RunExamplesKotlinTest(
- String pkg,
- String input,
- String compiler,
- String mode,
- String mainClass,
- String output) {
- super(pkg, input, compiler, mode, mainClass, output);
- }
-}
diff --git a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
index 2773cf1..52480be 100644
--- a/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
+++ b/src/test/java/com/android/tools/r8/RunExamplesAndroidOTest.java
@@ -9,15 +9,19 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import com.android.tools.r8.ToolHelper.DexVm;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.OffOrAuto;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.StringUtils.BraceType;
import com.android.tools.r8.utils.TestDescriptionWatcher;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
@@ -27,6 +31,8 @@
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
+import com.google.common.collect.Sets;
+import com.google.common.collect.Sets.SetView;
import com.google.common.io.ByteStreams;
import java.io.IOException;
import java.io.InputStream;
@@ -35,13 +41,12 @@
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.concurrent.ExecutionException;
+import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Predicate;
import java.util.function.UnaryOperator;
@@ -114,6 +119,24 @@
return withBuilderTransformation(builder -> builder.addMainDexClasses(classes));
}
+ C withMainDexKeepClassRules(List<String> classes) {
+ return withBuilderTransformation(
+ builder -> {
+ if (builder instanceof D8Command.Builder) {
+ ((D8Command.Builder) builder)
+ .addMainDexRules(
+ ListUtils.map(classes, c -> "-keep class " + c), Origin.unknown());
+ } else if (builder instanceof R8Command.Builder) {
+ ((R8Command.Builder) builder)
+ .addMainDexRules(
+ ListUtils.map(classes, c -> "-keep class " + c), Origin.unknown());
+ } else {
+ fail("Unexpected builder type: " + builder.getClass());
+ }
+ return builder;
+ });
+ }
+
C withInterfaceMethodDesugaring(OffOrAuto behavior) {
return withOptionConsumer(o -> o.interfaceMethodDesugaring = behavior);
}
@@ -465,15 +488,20 @@
testIntermediateWithMainDexList(
"lambdadesugaring",
1,
- "lambdadesugaring.LambdaDesugaring$I");
+ ImmutableList.of("lambdadesugaring.LambdaDesugaring$I"),
+ ImmutableList.of());
}
@Test
public void testLambdaDesugaringWithMainDexList2() throws Throwable {
// Main dex class has many lambdas.
- testIntermediateWithMainDexList("lambdadesugaring",
- 33,
- "lambdadesugaring.LambdaDesugaring$Refs$B");
+ testIntermediateWithMainDexList(
+ "lambdadesugaring",
+ // TODO(b/180074885): Over approximation not present in R8.
+ this instanceof R8RunExamplesAndroidOTest ? 51 : 52,
+ ImmutableList.of("lambdadesugaring.LambdaDesugaring$Refs$B"),
+ // TODO(b/180074885): Over approximation due to invoke-dynamic reference adds as dependency.
+ ImmutableList.of("lambdadesugaring.LambdaDesugaring$Refs$D"));
}
@Test
@@ -483,7 +511,11 @@
"interfacemethods",
Paths.get(ToolHelper.EXAMPLES_ANDROID_N_BUILD_DIR, "interfacemethods" + JAR_EXTENSION),
2,
- "interfacemethods.I1");
+ ImmutableList.of("interfacemethods.I1"),
+ // TODO(b/180074885): Over approximation due to including I1-CC by being derived from I1,
+ // but after desugaring I1 does not reference I1$-CC (the static method is moved), so it
+ // is incorrect to include I1-CC in the main dex.
+ ImmutableList.of("interfacemethods.I1$-CC"));
}
@@ -494,7 +526,11 @@
"interfacemethods",
Paths.get(ToolHelper.EXAMPLES_ANDROID_N_BUILD_DIR, "interfacemethods" + JAR_EXTENSION),
2,
- "interfacemethods.I2");
+ ImmutableList.of("interfacemethods.I2"),
+ // TODO(b/180074885): Over approximation due to including I2$-CC by being derived from I2,
+ // but after desugaring I2 does not reference I2$-CC (the default method is moved), so it
+ // is incorrect to include I2$-CC in the main dex.
+ ImmutableList.of("interfacemethods.I2$-CC"));
}
@Test
@@ -510,20 +546,23 @@
private void testIntermediateWithMainDexList(
String packageName,
int expectedMainDexListSize,
- String... mainDexClasses)
+ List<String> mainDexClasses,
+ List<String> mainDexOverApproximation)
throws Throwable {
testIntermediateWithMainDexList(
packageName,
Paths.get(EXAMPLE_DIR, packageName + JAR_EXTENSION),
expectedMainDexListSize,
- mainDexClasses);
+ mainDexClasses,
+ mainDexOverApproximation);
}
protected void testIntermediateWithMainDexList(
String packageName,
Path input,
int expectedMainDexListSize,
- String... mainDexClasses)
+ List<String> mainDexClasses,
+ List<String> mainDexOverApproximation)
throws Throwable {
AndroidApiLevel minApi = AndroidApiLevel.K;
@@ -534,16 +573,18 @@
.withMinApiLevel(minApi)
.withOptionConsumer(option -> option.minimalMainDex = true)
.withOptionConsumer(option -> option.enableInheritanceClassInDexDistributor = false)
- .withMainDexClass(mainDexClasses)
+ .withMainDexKeepClassRules(mainDexClasses)
.withKeepAll();
Path fullDexes = temp.getRoot().toPath().resolve(packageName + "full" + ZIP_EXTENSION);
full.build(input, fullDexes);
// Builds with intermediate in both output mode.
- Path dexesThroughIndexedIntermediate = buildDexThroughIntermediate(
- packageName, input, OutputMode.DexIndexed, minApi, mainDexClasses);
- Path dexesThroughFilePerInputClassIntermediate = buildDexThroughIntermediate(
- packageName, input, OutputMode.DexFilePerClassFile, minApi, mainDexClasses);
+ Path dexesThroughIndexedIntermediate =
+ buildDexThroughIntermediate(
+ packageName, input, OutputMode.DexIndexed, minApi, mainDexClasses);
+ Path dexesThroughFilePerInputClassIntermediate =
+ buildDexThroughIntermediate(
+ packageName, input, OutputMode.DexFilePerClassFile, minApi, mainDexClasses);
// Collect main dex types.
CodeInspector fullInspector = getMainDexInspector(fullDexes);
@@ -551,20 +592,45 @@
getMainDexInspector(dexesThroughIndexedIntermediate);
CodeInspector filePerInputClassIntermediateInspector =
getMainDexInspector(dexesThroughFilePerInputClassIntermediate);
- Collection<String> fullMainClasses = new HashSet<>();
+ Set<String> fullMainClasses = new HashSet<>();
fullInspector.forAllClasses(
clazz -> fullMainClasses.add(clazz.getFinalDescriptor()));
- Collection<String> indexedIntermediateMainClasses = new HashSet<>();
+ Set<String> indexedIntermediateMainClasses = new HashSet<>();
indexedIntermediateInspector.forAllClasses(
clazz -> indexedIntermediateMainClasses.add(clazz.getFinalDescriptor()));
- Collection<String> filePerInputClassIntermediateMainClasses = new HashSet<>();
+ Set<String> filePerInputClassIntermediateMainClasses = new HashSet<>();
filePerInputClassIntermediateInspector.forAllClasses(
clazz -> filePerInputClassIntermediateMainClasses.add(clazz.getFinalDescriptor()));
// Check.
Assert.assertEquals(expectedMainDexListSize, fullMainClasses.size());
- Assert.assertEquals(fullMainClasses, indexedIntermediateMainClasses);
- Assert.assertEquals(fullMainClasses, filePerInputClassIntermediateMainClasses);
+ SetView<String> adjustedFull =
+ Sets.difference(
+ fullMainClasses,
+ new HashSet<>(
+ ListUtils.map(mainDexOverApproximation, DescriptorUtils::javaTypeToDescriptor)));
+ assertEqualSets(adjustedFull, indexedIntermediateMainClasses);
+ assertEqualSets(adjustedFull, filePerInputClassIntermediateMainClasses);
+ }
+
+ <T> void assertEqualSets(Set<T> expected, Set<T> actual) {
+ SetView<T> missing = Sets.difference(expected, actual);
+ SetView<T> unexpected = Sets.difference(actual, expected);
+ if (missing.isEmpty() && unexpected.isEmpty()) {
+ return;
+ }
+ StringBuilder builder = new StringBuilder("Sets differ.");
+ if (!missing.isEmpty()) {
+ builder.append("\nMissing items: [\n ");
+ StringUtils.append(builder, missing, "\n ", BraceType.NONE);
+ builder.append("\n]");
+ }
+ if (!unexpected.isEmpty()) {
+ builder.append("\nUnexpected items: [\n ");
+ StringUtils.append(builder, unexpected, "\n ", BraceType.NONE);
+ builder.append("\n]");
+ }
+ fail(builder.toString());
}
protected Path buildDexThroughIntermediate(
@@ -572,7 +638,7 @@
Path input,
OutputMode outputMode,
AndroidApiLevel minApi,
- String... mainDexClasses)
+ List<String> mainDexClasses)
throws Throwable {
Path intermediateDex =
temp.getRoot().toPath().resolve(packageName + "intermediate" + ZIP_EXTENSION);
@@ -591,7 +657,7 @@
test(packageName + "dex", packageName, "N/A")
.withOptionConsumer(option -> option.minimalMainDex = true)
.withOptionConsumer(option -> option.enableInheritanceClassInDexDistributor = false)
- .withMainDexClass(mainDexClasses)
+ .withMainDexKeepClassRules(mainDexClasses)
.withMinApiLevel(minApi)
.withKeepAll();
@@ -644,8 +710,7 @@
}
}
- protected CodeInspector getMainDexInspector(Path zip)
- throws IOException, ExecutionException {
+ protected CodeInspector getMainDexInspector(Path zip) throws IOException {
try (ZipFile zipFile = new ZipFile(zip.toFile(), StandardCharsets.UTF_8)) {
try (InputStream in =
zipFile.getInputStream(zipFile.getEntry(ToolHelper.DEFAULT_DEX_FILENAME))) {
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 1ad5db8..aad62cb 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -4,7 +4,6 @@
package com.android.tools.r8;
-
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.dexsplitter.SplitterTestBase.RunInterface;
import com.android.tools.r8.references.MethodReference;
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 883a2b4..7721c08 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -103,14 +103,10 @@
public static final String EXAMPLES_ANDROID_N_DIR = TESTS_DIR + "examplesAndroidN/";
public static final String EXAMPLES_ANDROID_O_DIR = TESTS_DIR + "examplesAndroidO/";
public static final String EXAMPLES_ANDROID_P_DIR = TESTS_DIR + "examplesAndroidP/";
- public static final String EXAMPLES_KOTLIN_DIR = TESTS_DIR + "examplesKotlin/";
public static final String TESTS_BUILD_DIR = BUILD_DIR + "test/";
public static final String JDK_TESTS_BUILD_DIR = TESTS_BUILD_DIR + "jdk11Tests/";
public static final String EXAMPLES_BUILD_DIR = TESTS_BUILD_DIR + "examples/";
public static final String EXAMPLES_CF_DIR = EXAMPLES_BUILD_DIR + "classes/";
- public static final String EXAMPLES_KOTLIN_BUILD_DIR = TESTS_BUILD_DIR + "examplesKotlin/";
- public static final String EXAMPLES_KOTLIN_RESOURCE_DIR =
- TESTS_BUILD_DIR + "kotlinR8TestResources/";
public static final String EXAMPLES_ANDROID_N_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidN/";
public static final String EXAMPLES_ANDROID_O_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidO/";
public static final String EXAMPLES_ANDROID_P_BUILD_DIR = TESTS_BUILD_DIR + "examplesAndroidP/";
@@ -821,6 +817,8 @@
case J_MR1:
case J_MR2:
case K_WATCH:
+ // TODO(b/1813562600): Add android jar for S.
+ case S:
return false;
default:
return true;
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerBottomTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerBottomTest.java
new file mode 100644
index 0000000..3c71dbe
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerBottomTest.java
@@ -0,0 +1,116 @@
+// 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.accessrelaxation;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.utils.DescriptorUtils;
+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 PackagePrivateOverridePublicizerBottomTest extends TestBase {
+
+ private final TestParameters parameters;
+ private final String[] EXPECTED = new String[] {"SubViewModel.clear()", "ViewModel.clear()"};
+ private final String[] EXPECTED_ART_4 =
+ new String[] {"SubViewModel.clear()", "SubViewModel.clear()"};
+ private final String NEW_DESCRIPTOR = "Lfoo/bar/baz/SubViewModel;";
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public PackagePrivateOverridePublicizerBottomTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(ViewModel.class)
+ .addProgramClassFileData(
+ getSubViewModelInAnotherPackage(), getRewrittenSubViewModelInMain())
+ .run(parameters.getRuntime(), Main.class)
+ .apply(this::assertSuccessOutput);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(ViewModel.class)
+ .addProgramClassFileData(
+ getSubViewModelInAnotherPackage(), getRewrittenSubViewModelInMain())
+ .addKeepMainRule(Main.class)
+ .setMinApi(parameters.getApiLevel())
+ .enableInliningAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .allowAccessModification()
+ .run(parameters.getRuntime(), Main.class)
+ // TODO(b/181328496): This should be EXPECTED.
+ .assertSuccessWithOutputLines(EXPECTED_ART_4);
+ }
+
+ private byte[] getSubViewModelInAnotherPackage() throws Exception {
+ return transformer(SubViewModel.class).setClassDescriptor(NEW_DESCRIPTOR).transform();
+ }
+
+ private byte[] getRewrittenSubViewModelInMain() throws Exception {
+ return transformer(Main.class)
+ .replaceClassDescriptorInMethodInstructions(
+ DescriptorUtils.javaTypeToDescriptor(SubViewModel.class.getTypeName()), NEW_DESCRIPTOR)
+ .transform();
+ }
+
+ private void assertSuccessOutput(TestRunResult<?> result) {
+ if (parameters.isDexRuntime() && parameters.getDexRuntimeVersion().isDalvik()) {
+ result.assertSuccessWithOutputLines(EXPECTED_ART_4);
+ } else {
+ result.assertSuccessWithOutputLines(EXPECTED);
+ }
+ }
+
+ @SuppressWarnings("override") /* after changing the package the clear method is not overridden */
+ @NoVerticalClassMerging
+ public static class ViewModel {
+
+ @NeverInline
+ void clear() {
+ System.out.println("ViewModel.clear()");
+ }
+ }
+
+ @NeverClassInline
+ @SuppressWarnings("override") /* after changing the package the clear method is not overridden */
+ public static class /* foo.bar.baz. */ SubViewModel extends ViewModel {
+
+ @NeverInline
+ void clear() {
+ System.out.println("SubViewModel.clear()");
+ }
+
+ public void callBridge() {
+ clear();
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) {
+ SubViewModel viewModel = new SubViewModel();
+ viewModel.callBridge();
+ ((ViewModel) viewModel).clear();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerTest.java
index 630ff62..5a9da04 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/PackagePrivateOverridePublicizerTest.java
@@ -23,6 +23,7 @@
private final TestParameters parameters;
private final String[] EXPECTED = new String[] {"SubViewModel.clear()", "ViewModel.clear()"};
+ private final String[] R8_OUT = new String[] {"SubViewModel.clear()", "SubViewModel.clear()"};
@Parameters(name = "{0}")
public static TestParametersCollection data() {
@@ -50,12 +51,9 @@
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.allowAccessModification()
- .addOptionsModification(
- options -> {
- options.enablePackagePrivateAwarePublicization = true;
- })
.run(parameters.getRuntime(), Main.class)
- .apply(this::assertSuccessOutput);
+ // TODO(b/172496438): This should be EXPECTED.
+ .assertSuccessWithOutputLines(R8_OUT);
}
private void assertSuccessOutput(TestRunResult<?> result) {
diff --git a/src/test/java/com/android/tools/r8/cf/methodhandles/InvalidBootstrapMethodHandleTestClass.java b/src/test/java/com/android/tools/r8/cf/methodhandles/InvalidBootstrapMethodHandleTestClass.java
index 9040a68..d63ead6 100644
--- a/src/test/java/com/android/tools/r8/cf/methodhandles/InvalidBootstrapMethodHandleTestClass.java
+++ b/src/test/java/com/android/tools/r8/cf/methodhandles/InvalidBootstrapMethodHandleTestClass.java
@@ -25,6 +25,7 @@
public int nonStaticField = 42;
// Virtual method to target.
+ @Override
public CallSite virtualMethod(MethodHandles.Lookup caller, String name, MethodType type)
throws Exception {
return new ConstantCallSite(caller.findStatic(caller.lookupClass(), name, type));
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 04bb9d7..c551a26 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
@@ -32,18 +32,19 @@
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
+ .addKeepPackageNamesRule(Main.class.getPackage())
.addHorizontallyMergedClassesInspector(
HorizontallyMergedClassesInspector::assertNoClassesMerged)
.run(parameters.getRuntime(), Main.class)
- .assertFailureWithErrorThatMatches(
- allOf(
- containsString("java.lang.UnsatisfiedLinkError:"),
- containsString("com.android.tools.r8.classmerging.horizontal.b.a(")))
.inspectFailure(
codeInspector -> {
assertThat(codeInspector.clazz(A.class), isPresent());
assertThat(codeInspector.clazz(B.class), isPresent());
- });
+ })
+ .assertFailureWithErrorThatMatches(
+ allOf(
+ containsString("java.lang.UnsatisfiedLinkError:"),
+ containsString("com.android.tools.r8.classmerging.horizontal.b.a(")));
}
@NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
index 034f226..68e882e 100644
--- a/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
+++ b/src/test/java/com/android/tools/r8/compatproguard/CompatKeepClassMemberNamesTestRunner.java
@@ -388,7 +388,7 @@
buildWithMemberNamesRule(testForR8(parameters.getBackend())).compile());
}
- // Tests for "-keepclassmembernames" and *no* minification.
+ // Tests for "-keepclassmembernames" and minification.
private <
C extends BaseCompilerCommand,
diff --git a/src/test/java/com/android/tools/r8/compatproguard/KeepClassMemberNamesMinificationTest.java b/src/test/java/com/android/tools/r8/compatproguard/KeepClassMemberNamesMinificationTest.java
new file mode 100644
index 0000000..009cf9f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/compatproguard/KeepClassMemberNamesMinificationTest.java
@@ -0,0 +1,120 @@
+// 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.compatproguard;
+
+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.Assume.assumeTrue;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.ProguardVersion;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KeepClassMemberNamesMinificationTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public KeepClassMemberNamesMinificationTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testForRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClasses(Main.class, A.class, ReflectiveCallerOfA.class)
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello World!", "Hello World!");
+ }
+
+ @Test
+ public void testPG() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testKeepNames(testForProguard(ProguardVersion.V7_0_0).addKeepRules("-dontwarn"));
+ }
+
+ @Test
+ public void testR8Compat() throws Exception {
+ testKeepNames(
+ testForR8Compat(parameters.getBackend())
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations());
+ }
+
+ @Test
+ public void testR8Full() throws Exception {
+ testKeepNames(
+ testForR8(parameters.getBackend())
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations());
+ }
+
+ private void testKeepNames(TestShrinkerBuilder<?, ?, ?, ?, ?> shrinkerBuilder) throws Exception {
+ shrinkerBuilder
+ .addProgramClasses(Main.class, A.class, ReflectiveCallerOfA.class)
+ .addKeepMainRule(Main.class)
+ .addKeepClassAndMembersRulesWithAllowObfuscation(A.class)
+ .addKeepRules("-keepclassmembernames class ** { *; }")
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject aClass = inspector.clazz(A.class);
+ assertThat(aClass, isPresentAndRenamed());
+ assertThat(aClass.uniqueFieldWithName("foo"), isPresentAndNotRenamed());
+ assertThat(aClass.uniqueMethodWithName("foo"), isPresentAndNotRenamed());
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello World!", "Hello World!");
+ }
+
+ @NeverClassInline
+ public static class A {
+
+ public String foo = "Hello World!";
+
+ public void foo() {
+ System.out.println("Hello World!");
+ }
+
+ @NeverInline
+ public void callMySelf() throws Exception {
+ ReflectiveCallerOfA.callA(this.getClass().getName());
+ }
+ }
+
+ public static class ReflectiveCallerOfA {
+
+ @NeverInline
+ public static void callA(String className) throws Exception {
+ Class<?> aClass = Class.forName(className);
+ Object o = aClass.getDeclaredConstructor().newInstance();
+ System.out.println(aClass.getDeclaredField("foo").get(o));
+ aClass.getDeclaredMethod("foo").invoke(o);
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) throws Exception {
+ new A().callMySelf();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/ContinuousKotlinSteppingTest.java b/src/test/java/com/android/tools/r8/debug/ContinuousKotlinSteppingTest.java
new file mode 100644
index 0000000..539af51
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debug/ContinuousKotlinSteppingTest.java
@@ -0,0 +1,49 @@
+// Copyright (c) 2017, 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.debug;
+
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+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 ContinuousKotlinSteppingTest extends DebugTestBase {
+
+ private static final String MAIN_METHOD_NAME = "main";
+
+ @Parameters(name = "{0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+ }
+
+ private final TestParameters parameters;
+ private final KotlinTestParameters kotlinParameters;
+
+ public ContinuousKotlinSteppingTest(
+ TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ this.parameters = parameters;
+ this.kotlinParameters = kotlinParameters;
+ }
+
+ @Test
+ public void testContinuousSingleStepKotlinApp() throws Throwable {
+ KotlinDebugD8Config d8Config =
+ KotlinDebugD8Config.build(kotlinParameters, parameters.getApiLevel());
+ runContinuousTest("KotlinApp", d8Config, MAIN_METHOD_NAME);
+ }
+
+ @Test
+ public void testContinuousSingleStepKotlinInline() throws Throwable {
+ KotlinDebugD8Config d8Config =
+ KotlinDebugD8Config.build(kotlinParameters, parameters.getApiLevel());
+ runContinuousTest("KotlinInline", d8Config, MAIN_METHOD_NAME);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/ContinuousSteppingTest.java b/src/test/java/com/android/tools/r8/debug/ContinuousSteppingTest.java
index 4552be6..beed8fc 100644
--- a/src/test/java/com/android/tools/r8/debug/ContinuousSteppingTest.java
+++ b/src/test/java/com/android/tools/r8/debug/ContinuousSteppingTest.java
@@ -4,8 +4,12 @@
package com.android.tools.r8.debug;
+import com.android.tools.r8.KotlinCompilerTool;
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestBase.KotlinCompileMemoizer;
import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -26,16 +30,12 @@
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
-import java.util.HashMap;
import java.util.List;
-import java.util.Map;
+import java.util.function.Function;
import java.util.function.Predicate;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.stream.Collectors;
-import org.apache.harmony.jpda.tests.framework.jdwp.Value;
-import org.junit.AfterClass;
-import org.junit.Assert;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
@@ -47,14 +47,11 @@
private static final String MAIN_METHOD_NAME = "main";
- private static final TemporaryFolder testTemp = ToolHelper.getTemporaryFolderForTest();
-
// A list of self-contained jars to process (which do not depend on other jar files).
private static List<Pair<Path, Predicate<Version>>> listOfJars() {
return new ConfigListBuilder()
.add(DebugTestBase.DEBUGGEE_JAR, ContinuousSteppingTest::allVersions)
.add(DebugTestBase.DEBUGGEE_JAVA8_JAR, ContinuousSteppingTest::allVersions)
- .addAllKotlinDebugJars(testTemp, ContinuousSteppingTest::allVersions)
.addAll(
findAllJarsIn(Paths.get(ToolHelper.EXAMPLES_ANDROID_N_BUILD_DIR)),
ContinuousSteppingTest::fromAndroidN)
@@ -64,8 +61,6 @@
.build();
}
- private static final Map<Path, DebugTestConfig> compiledJarConfig = new HashMap<>();
-
private final String mainClass;
private final Path jarPath;
@@ -87,9 +82,15 @@
public ConfigListBuilder addAllKotlinDebugJars(
TemporaryFolder temp, Predicate<Version> predicate) {
+ KotlinCompileMemoizer compiledJars =
+ KotlinTestBase.getCompileMemoizer(
+ KotlinTestBase.getKotlinFilesInResource("debug"),
+ CfRuntime.getCheckedInJdk9(),
+ temp)
+ .configure(KotlinCompilerTool::includeRuntime);
for (KotlinTestParameters kotlinParameter :
TestBase.getKotlinTestParameters().withAllCompilersAndTargetVersions().build()) {
- add(KotlinD8Config.compileKotlinMemoized.apply(temp, kotlinParameter), predicate);
+ add(compiledJars.getForConfiguration(kotlinParameter), predicate);
}
return this;
}
@@ -117,14 +118,8 @@
}
}
- @AfterClass
- public static void tearDown() {
- testTemp.delete();
- }
-
@Parameters(name = "{0} from {1}")
public static Collection<Object[]> getData() throws IOException {
- testTemp.create();
List<Object[]> testCases = new ArrayList<>();
for (Pair<Path, Predicate<Version>> pair : listOfJars()) {
if (pair.getSecond().test(ToolHelper.getDexVm().getVersion())) {
@@ -133,14 +128,14 @@
for (String className : mainClasses) {
testCases.add(new Object[]{className, jarPath});
}
-
- DebugTestConfig config = new D8DebugTestConfig().compileAndAdd(testTemp, jarPath);
- compiledJarConfig.put(jarPath, config);
}
}
return testCases;
}
+ private static final Function<Path, DebugTestConfig> compiledJars =
+ memoizeFunction(path -> new D8DebugTestConfig().compileAndAdd(getStaticTemp(), path));
+
public ContinuousSteppingTest(String mainClass, Path jarPath) {
this.mainClass = mainClass;
this.jarPath = jarPath;
@@ -148,10 +143,9 @@
@Test
public void testContinuousSingleStep() throws Throwable {
- assert compiledJarConfig.containsKey(jarPath);
- DebugTestConfig config = compiledJarConfig.get(jarPath);
+ DebugTestConfig config = compiledJars.apply(jarPath);
assert config != null;
- runContinuousTest(mainClass, config);
+ runContinuousTest(mainClass, config, MAIN_METHOD_NAME);
}
// Returns a list of classes with a "public static void main(String[])" method in the given jar
@@ -206,22 +200,4 @@
&& m.getParameterCount() == 1
&& m.getParameterTypes()[0] == String[].class;
}
-
- private void runContinuousTest(String debuggeeClassName, DebugTestConfig config)
- throws Throwable {
- runDebugTest(
- config,
- debuggeeClassName,
- breakpoint(debuggeeClassName, MAIN_METHOD_NAME),
- run(),
- stepUntil(StepKind.OVER, StepLevel.INSTRUCTION, debuggeeState -> {
- // Fetch local variables.
- Map<String, Value> localValues = debuggeeState.getLocalValues();
- Assert.assertNotNull(localValues);
-
- // Always step until we actually exit the program.
- return false;
- }));
- }
-
}
diff --git a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
index 6dc126c..a083bcf 100644
--- a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
+++ b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java
@@ -2208,4 +2208,24 @@
}
}
}
+
+ protected void runContinuousTest(
+ String debuggeeClassName, DebugTestConfig config, String mainMethodName) throws Throwable {
+ runDebugTest(
+ config,
+ debuggeeClassName,
+ breakpoint(debuggeeClassName, mainMethodName),
+ run(),
+ stepUntil(
+ StepKind.OVER,
+ StepLevel.INSTRUCTION,
+ debuggeeState -> {
+ // Fetch local variables.
+ Map<String, Value> localValues = debuggeeState.getLocalValues();
+ Assert.assertNotNull(localValues);
+
+ // Always step until we actually exit the program.
+ return false;
+ }));
+ }
}
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinD8Config.java b/src/test/java/com/android/tools/r8/debug/KotlinD8Config.java
deleted file mode 100644
index a7e31a4..0000000
--- a/src/test/java/com/android/tools/r8/debug/KotlinD8Config.java
+++ /dev/null
@@ -1,63 +0,0 @@
-// Copyright (c) 2018, 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.debug;
-
-import static com.android.tools.r8.TestBase.kotlinc;
-import static com.android.tools.r8.TestBase.memoizeBiFunction;
-
-import com.android.tools.r8.KotlinTestBase;
-import com.android.tools.r8.KotlinTestParameters;
-import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.TestBase;
-import com.android.tools.r8.TestRuntime;
-import com.android.tools.r8.utils.AndroidApiLevel;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.util.Collections;
-import java.util.function.BiFunction;
-import org.junit.rules.TemporaryFolder;
-
-/** Shared test configuration for D8 compiled resources from the "kotlinR8TestResources/debug". */
-class KotlinD8Config extends D8DebugTestConfig {
-
- public static BiFunction<TemporaryFolder, KotlinTestParameters, Path> compileKotlinMemoized =
- memoizeBiFunction(KotlinD8Config::compileWithKotlinC);
-
- private static Path compileWithKotlinC(TemporaryFolder temp, KotlinTestParameters parameters)
- throws IOException {
- return kotlinc(
- TestRuntime.getCheckedInJdk9(),
- temp,
- parameters.getCompiler(),
- parameters.getTargetVersion())
- .addSourceFiles(KotlinTestBase.getKotlinFilesInResource("debug"))
- .includeRuntime()
- .compile();
- }
-
- private static BiFunction<KotlinTestParameters, AndroidApiLevel, Path> compiledResourcesMemoized =
- memoizeBiFunction(KotlinD8Config::getCompiledResources);
-
- private static Path getCompiledResources(
- KotlinTestParameters kotlinTestParameters, AndroidApiLevel apiLevel) throws IOException {
- Path outputPath =
- TestBase.getStaticTemp().newFolder().toPath().resolve("d8_debug_test_resources_kotlin.jar");
- Path kotlinJar = compileKotlinMemoized.apply(TestBase.getStaticTemp(), kotlinTestParameters);
- D8DebugTestConfig.d8Compile(Collections.singletonList(kotlinJar), apiLevel, null)
- .write(outputPath, OutputMode.DexIndexed);
- return outputPath;
- }
-
- public static KotlinD8Config build(
- KotlinTestParameters kotlinTestParameters, AndroidApiLevel apiLevel) {
- try {
- KotlinD8Config kotlinD8Config = new KotlinD8Config();
- kotlinD8Config.addPaths(compiledResourcesMemoized.apply(kotlinTestParameters, apiLevel));
- return kotlinD8Config;
- } catch (Throwable e) {
- throw new RuntimeException(e);
- }
- }
-}
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinDebugD8Config.java b/src/test/java/com/android/tools/r8/debug/KotlinDebugD8Config.java
new file mode 100644
index 0000000..348d43a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debug/KotlinDebugD8Config.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2018, 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.debug;
+
+import static com.android.tools.r8.KotlinTestBase.getCompileMemoizer;
+import static com.android.tools.r8.TestBase.memoizeBiFunction;
+
+import com.android.tools.r8.KotlinCompilerTool;
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestBase.KotlinCompileMemoizer;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.function.BiFunction;
+
+/** Shared test configuration for D8 compiled resources from the "kotlinR8TestResources/debug". */
+class KotlinDebugD8Config extends D8DebugTestConfig {
+
+ static final KotlinCompileMemoizer compiledKotlinJars =
+ getCompileMemoizer(KotlinTestBase.getKotlinFilesInResource("debug"))
+ .configure(KotlinCompilerTool::includeRuntime);
+
+ private static final BiFunction<KotlinTestParameters, AndroidApiLevel, Path>
+ compiledResourcesMemoized = memoizeBiFunction(KotlinDebugD8Config::getCompiledResources);
+
+ private static Path getCompiledResources(
+ KotlinTestParameters kotlinTestParameters, AndroidApiLevel apiLevel) throws IOException {
+ Path outputPath =
+ TestBase.getStaticTemp().newFolder().toPath().resolve("d8_debug_test_resources_kotlin.jar");
+ Path kotlinJar = compiledKotlinJars.getForConfiguration(kotlinTestParameters);
+ D8DebugTestConfig.d8Compile(Collections.singletonList(kotlinJar), apiLevel, null)
+ .write(outputPath, OutputMode.DexIndexed);
+ return outputPath;
+ }
+
+ public static KotlinDebugD8Config build(
+ KotlinTestParameters kotlinTestParameters, AndroidApiLevel apiLevel) {
+ try {
+ KotlinDebugD8Config kotlinDebugD8Config = new KotlinDebugD8Config();
+ kotlinDebugD8Config.addPaths(compiledResourcesMemoized.apply(kotlinTestParameters, apiLevel));
+ return kotlinDebugD8Config;
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinInlineTest.java b/src/test/java/com/android/tools/r8/debug/KotlinInlineTest.java
index 00333e0..d205f26 100644
--- a/src/test/java/com/android/tools/r8/debug/KotlinInlineTest.java
+++ b/src/test/java/com/android/tools/r8/debug/KotlinInlineTest.java
@@ -39,8 +39,8 @@
this.kotlinParameters = kotlinParameters;
}
- protected KotlinD8Config getD8Config() {
- return KotlinD8Config.build(kotlinParameters, parameters.getApiLevel());
+ protected KotlinDebugD8Config getD8Config() {
+ return KotlinDebugD8Config.build(kotlinParameters, parameters.getApiLevel());
}
@Test
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinLoopD8Config.java b/src/test/java/com/android/tools/r8/debug/KotlinLoopD8Config.java
new file mode 100644
index 0000000..c1f20d3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/debug/KotlinLoopD8Config.java
@@ -0,0 +1,52 @@
+// Copyright (c) 2018, 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.debug;
+
+import static com.android.tools.r8.KotlinTestBase.getCompileMemoizer;
+import static com.android.tools.r8.TestBase.memoizeBiFunction;
+
+import com.android.tools.r8.KotlinCompilerTool;
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestBase.KotlinCompileMemoizer;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.Collections;
+import java.util.function.BiFunction;
+
+/** Shared test configuration for D8 compiled resources from the "kotlinR8TestResources/loops". */
+class KotlinLoopD8Config extends D8DebugTestConfig {
+
+ static final KotlinCompileMemoizer compiledKotlinJars =
+ getCompileMemoizer(KotlinTestBase.getKotlinFilesInResource("loops"))
+ .configure(KotlinCompilerTool::includeRuntime);
+
+ private static final BiFunction<KotlinTestParameters, AndroidApiLevel, Path>
+ compiledResourcesMemoized = memoizeBiFunction(KotlinLoopD8Config::getCompiledResources);
+
+ private static Path getCompiledResources(
+ KotlinTestParameters kotlinTestParameters, AndroidApiLevel apiLevel) throws IOException {
+ Path outputPath =
+ TestBase.getStaticTemp().newFolder().toPath().resolve("d8_debug_test_resources_kotlin.jar");
+ Path kotlinJar = compiledKotlinJars.getForConfiguration(kotlinTestParameters);
+ D8DebugTestConfig.d8Compile(Collections.singletonList(kotlinJar), apiLevel, null)
+ .write(outputPath, OutputMode.DexIndexed);
+ return outputPath;
+ }
+
+ public static KotlinLoopD8Config build(
+ KotlinTestParameters kotlinTestParameters, AndroidApiLevel apiLevel) {
+ try {
+ KotlinLoopD8Config kotlinDebugD8Config = new KotlinLoopD8Config();
+ kotlinDebugD8Config.addPaths(compiledResourcesMemoized.apply(kotlinTestParameters, apiLevel));
+ return kotlinDebugD8Config;
+ } catch (Throwable e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinLoopTest.java b/src/test/java/com/android/tools/r8/debug/KotlinLoopTest.java
index 85c3ec5..ef55a6d 100644
--- a/src/test/java/com/android/tools/r8/debug/KotlinLoopTest.java
+++ b/src/test/java/com/android/tools/r8/debug/KotlinLoopTest.java
@@ -3,15 +3,34 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.debug;
-import com.android.tools.r8.ToolHelper;
-import java.nio.file.Paths;
+import com.android.tools.r8.KotlinTestParameters;
+import com.android.tools.r8.TestParameters;
+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 KotlinLoopTest extends KotlinDebugTestBase {
+ private final TestParameters parameters;
+ private final KotlinTestParameters kotlinParameters;
+
+ @Parameters(name = "{0}, {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
+ }
+
+ public KotlinLoopTest(TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ this.parameters = parameters;
+ this.kotlinParameters = kotlinParameters;
+ }
+
DebugTestConfig config() {
- return new D8DebugTestConfig()
- .compileAndAdd(temp, Paths.get(ToolHelper.EXAMPLES_KOTLIN_BUILD_DIR, "loops.jar"));
+ return KotlinLoopD8Config.build(kotlinParameters, parameters.getApiLevel());
}
@Test
diff --git a/src/test/java/com/android/tools/r8/debug/KotlinTest.java b/src/test/java/com/android/tools/r8/debug/KotlinTest.java
index 07e9e05..4c9f8c0 100644
--- a/src/test/java/com/android/tools/r8/debug/KotlinTest.java
+++ b/src/test/java/com/android/tools/r8/debug/KotlinTest.java
@@ -32,8 +32,8 @@
this.kotlinParameters = kotlinParameters;
}
- protected KotlinD8Config getD8Config() {
- return KotlinD8Config.build(kotlinParameters, parameters.getApiLevel());
+ protected KotlinDebugD8Config getD8Config() {
+ return KotlinDebugD8Config.build(kotlinParameters, parameters.getApiLevel());
}
// TODO(shertz) simplify test
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java b/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java
index 05f84af..81f0674 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java
@@ -153,7 +153,7 @@
testForD8(parameters.getBackend())
.addProgramClasses(CLASSES)
.setMinApi(parameters.getApiLevel())
- .addMainDexListClasses(MiniAssert.class, TestClass.class, User2.class)
+ .addMainDexRules(keepMainProguardConfiguration(TestClass.class))
.setProgramConsumer(mainDexConsumer)
.compile()
.inspect(this::checkExpectedSynthetics)
@@ -185,44 +185,8 @@
testForD8()
.addProgramFiles(perClassOutput)
.setMinApi(parameters.getApiLevel())
- .addMainDexListClasses(MiniAssert.class, TestClass.class, User2.class)
- .setProgramConsumer(mainDexConsumer)
- .compile()
- .inspect(this::checkExpectedSynthetics)
- .run(parameters.getRuntime(), TestClass.class, getRunArgs())
- .assertSuccessWithOutput(EXPECTED);
- checkMainDex(mainDexConsumer);
- }
-
- // TODO(b/168584485): This test should be removed once support is dropped.
- @Test
- public void testD8MergingWithTraceCf() throws Exception {
- assumeTrue(parameters.isDexRuntime());
- Path out1 =
- testForD8()
- .addProgramClasses(User1.class)
- .addClasspathClasses(CLASSES)
- .setIntermediate(true)
- .setMinApi(parameters.getApiLevel())
- .compile()
- .writeToZip();
-
- Path out2 =
- testForD8()
- .addProgramClasses(User2.class)
- .addClasspathClasses(CLASSES)
- .setIntermediate(true)
- .setMinApi(parameters.getApiLevel())
- .compile()
- .writeToZip();
-
- MainDexConsumer mainDexConsumer = new MainDexConsumer();
- testForD8(parameters.getBackend())
- .addProgramClasses(TestClass.class, MiniAssert.class)
- .addProgramFiles(out1, out2)
- .setMinApi(parameters.getApiLevel())
- .addMainDexListClassReferences(
- traceMainDex(CLASSES, Collections.emptyList()).getMainDexList())
+ // Trace the classes run by main which will pick up their dependencies.
+ .addMainDexRules(keepMainProguardConfiguration(TestClass.class))
.setProgramConsumer(mainDexConsumer)
.compile()
.inspect(this::checkExpectedSynthetics)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
index ccd3cdf..0ee446d 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/ConversionIntroduceInterfaceMethodTest.java
@@ -99,10 +99,8 @@
shrinkDesugaredLibrary)
.addRunClasspathFiles(CUSTOM_LIB)
.run(parameters.getRuntime(), Executor.class)
- .apply(
- r ->
- r.assertSuccessWithOutput(
- supportAllCallbacksFromLibrary ? EXPECTED_RESULT : FAILING_EXPECTED_RESULT));
+ .assertSuccessWithOutput(
+ supportAllCallbacksFromLibrary ? EXPECTED_RESULT : FAILING_EXPECTED_RESULT);
}
private void assertDoubleForEach(CodeInspector inspector) {
@@ -164,10 +162,8 @@
shrinkDesugaredLibrary)
.addRunClasspathFiles(CUSTOM_LIB)
.run(parameters.getRuntime(), Executor.class)
- .apply(
- r ->
- r.assertSuccessWithOutput(
- supportAllCallbacksFromLibrary ? EXPECTED_RESULT : FAILING_EXPECTED_RESULT));
+ .assertSuccessWithOutput(
+ supportAllCallbacksFromLibrary ? EXPECTED_RESULT : FAILING_EXPECTED_RESULT);
}
static class CustomLibClass {
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIProgramTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIProgramTest.java
index b62045b..a96a874 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIProgramTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/conversiontests/DuplicateAPIProgramTest.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.desugar.desugaredlibrary.DesugaredLibraryTestBase;
-import com.android.tools.r8.desugar.desugaredlibrary.conversiontests.MoreFunctionConversionTest.CustomLibClass;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesUpdateTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesUpdateTest.java
index f1884e9..2abe133 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesUpdateTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestAttributesUpdateTest.java
@@ -96,6 +96,7 @@
})
.addProgramFiles(classesMatching(outerNestName))
.applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
+ .addKeepPackageNamesRule("nesthostexample")
.addInliningAnnotations()
.compile()
.inspect(
diff --git a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
index 073c7b1..9f41a17 100644
--- a/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/nestaccesscontrol/NestClassMergingTest.java
@@ -99,6 +99,7 @@
.enableInliningAnnotations()
.addProgramFiles(bothNestsAndOutsideClassToCompile)
.applyIf(parameters.isCfRuntime(), Jdk9TestUtils.addJdk9LibraryFiles(temp))
+ .addKeepPackageNamesRule("nesthostexample")
.compile()
.inspect(NestAttributesUpdateTest::assertNestAttributesCorrect);
for (int i = 0; i < mainClasses.length; i++) {
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingMergeEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingMergeEnumUnboxingTest.java
index 227ce07..7cc81c3 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingMergeEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingMergeEnumUnboxingTest.java
@@ -86,6 +86,7 @@
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.minification(minification)
+ .addKeepPackageNamesRule(libClass.getPackage())
.setMinApi(parameters.getApiLevel())
.compile()
.writeToZip();
diff --git a/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java b/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
index 4be7975..a94f02a 100644
--- a/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
@@ -49,8 +49,9 @@
if (parameters.getRuntime().asCf().isNewerThan(CfVm.JDK8)) {
runResult.assertFailureWithErrorThatMatches(
containsString(
- "java.lang.IncompatibleClassChangeError: Method"
- + " com.android.tools.r8.graph.invokestatic.InvokeStaticOnInterfaceTest$I.foo()V"
+ "java.lang.IncompatibleClassChangeError: Method "
+ + I.class.getTypeName()
+ + ".foo()V"
+ " must be InterfaceMethodref constant"));
} else {
runResult.assertSuccessWithOutputLines("Hello World!");
@@ -79,13 +80,14 @@
.enableInliningAnnotations()
.enableNoVerticalClassMergingAnnotations()
.addOptionsModification(o -> o.testing.allowInvokeErrors = true)
+ .noMinification()
.addKeepMainRule(Main.class)
.run(parameters.getRuntime(), Main.class);
if (parameters.getRuntime().asCf().isNewerThan(CfVm.JDK8)) {
runResult.assertFailureWithErrorThatMatches(
containsString(
"java.lang.IncompatibleClassChangeError: Method"
- + " com.android.tools.r8.graph.invokestatic.a.a()V"
+ + " com.android.tools.r8.graph.invokestatic.InvokeStaticOnInterfaceTest$I.foo()V"
+ " must be InterfaceMethodref constant"));
} else {
runResult.assertSuccessWithOutputLines("Hello World!");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/switches/DeadSwitchCaseWithSharedTargetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/switches/DeadSwitchCaseWithSharedTargetTest.java
new file mode 100644
index 0000000..6fd4739
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/switches/DeadSwitchCaseWithSharedTargetTest.java
@@ -0,0 +1,82 @@
+// Copyright (c) 2021, 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.switches;
+
+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;
+
+@RunWith(Parameterized.class)
+public class DeadSwitchCaseWithSharedTargetTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public DeadSwitchCaseWithSharedTargetTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepRules(
+ "-assumevalues class " + Main.class.getTypeName() + " {",
+ " static int FIELD return 27..30;",
+ "}")
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("?", "?", "O", "P", "Q", "R", "?");
+ }
+
+ static class Main {
+
+ static int FIELD;
+ static boolean alwaysTrue = System.currentTimeMillis() >= 0;
+
+ public static void main(String[] args) {
+ test(25);
+ test(26);
+ test(27);
+ test(28);
+ test(29);
+ test(30);
+ test(31);
+ }
+
+ static void test(int i) {
+ if (alwaysTrue) {
+ FIELD = i;
+ }
+ switch (FIELD) {
+ case 26:
+ case 27:
+ System.out.println("O");
+ break;
+ case 28:
+ System.out.println("P");
+ break;
+ case 29:
+ System.out.println("Q");
+ break;
+ case 30:
+ System.out.println("R");
+ break;
+ default:
+ System.out.println("?");
+ break;
+ }
+ }
+ }
+}
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 679177e..68614ad 100644
--- a/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/ProcessKotlinStdlibTest.java
@@ -74,4 +74,20 @@
public void testDontObfuscate() throws Exception {
test(ImmutableList.of("-dontobfuscate"));
}
+
+ @Test
+ public void testRepackage() throws Exception {
+ test(
+ ImmutableList.of(
+ "-keep,allowobfuscation class kotlin.Metadata { *; }", "-repackageclasses ''"));
+ }
+
+ @Test
+ public void testRepackageWithKeepAttributes() throws Exception {
+ test(
+ ImmutableList.of(
+ "-keep,allowobfuscation class kotlin.Metadata { *; }",
+ "-repackageclasses ''",
+ "-keepattributes *"));
+ }
}
diff --git a/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java b/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java
index 265aa24..9c01d63 100644
--- a/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/optimize/switches/KotlinEnumSwitchTest.java
@@ -10,12 +10,12 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertNotEquals;
-import com.android.tools.r8.TestBase;
+import com.android.tools.r8.KotlinCompilerTool;
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
-import java.nio.file.Paths;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -23,18 +23,28 @@
import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
-public class KotlinEnumSwitchTest extends TestBase {
+public class KotlinEnumSwitchTest extends KotlinTestBase {
private final boolean enableSwitchMapRemoval;
private final TestParameters parameters;
- @Parameters(name = "{1}, enable switch map removal: {0}")
+ @Parameters(name = "{1}, enable switch map removal: {0}, {2}")
public static List<Object[]> data() {
return buildParameters(
- BooleanUtils.values(), getTestParameters().withAllRuntimesAndApiLevels().build());
+ BooleanUtils.values(),
+ getTestParameters().withAllRuntimesAndApiLevels().build(),
+ getKotlinTestParameters().withAllCompilersAndTargetVersions().build());
}
- public KotlinEnumSwitchTest(boolean enableSwitchMapRemoval, TestParameters parameters) {
+ private static final KotlinCompileMemoizer kotlinJars =
+ getCompileMemoizer(getKotlinFilesInResource("enumswitch"))
+ .configure(KotlinCompilerTool::includeRuntime);
+
+ public KotlinEnumSwitchTest(
+ boolean enableSwitchMapRemoval,
+ TestParameters parameters,
+ KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.enableSwitchMapRemoval = enableSwitchMapRemoval;
this.parameters = parameters;
}
@@ -43,8 +53,7 @@
public void test() throws Exception {
testForR8(parameters.getBackend())
.addProgramFiles(
- Paths.get(ToolHelper.EXAMPLES_KOTLIN_BUILD_DIR, "enumswitch.jar"),
- getMostRecentKotlinAnnotationJar())
+ kotlinJars.getForConfiguration(kotlinParameters), getMostRecentKotlinAnnotationJar())
.addKeepMainRule("enumswitch.EnumSwitchKt")
.addOptionsModification(
options -> {
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java
index 1bbcb9e..d3d99ee 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListOutputTest.java
@@ -116,12 +116,11 @@
@Test
public void testD8DesugaredLambdasInMainDexList() throws Exception {
- Path mainDexList = writeTextToTempFile(testClassMainDexName);
TestMainDexListConsumer consumer = new TestMainDexListConsumer();
testForD8()
.setMinApi(AndroidApiLevel.K)
.addProgramClasses(ImmutableList.of(TestClass.class, MyConsumer.class))
- .addMainDexListFiles(ImmutableList.of(mainDexList))
+ .addMainDexListClasses(TestClass.class)
.setMainDexListConsumer(consumer)
.compile();
assertTrue(consumer.called);
@@ -129,7 +128,6 @@
@Test
public void testD8DesugaredLambdasInMainDexListMerging() throws Exception {
- Path mainDexList = writeTextToTempFile(testClassMainDexName);
// Build intermediate dex code first.
Path dexOutput =
testForD8()
@@ -143,7 +141,7 @@
testForD8()
.setMinApi(AndroidApiLevel.K)
.addProgramFiles(dexOutput)
- .addMainDexListFiles(ImmutableList.of(mainDexList))
+ .addMainDexKeepClassRules(TestClass.class)
.setMainDexListConsumer(consumer)
.compile();
assertTrue(consumer.called);
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java
index 9fa7fe9..5e88d7d 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexWithSynthesizedClassesTest.java
@@ -72,7 +72,7 @@
D8TestCompileResult compileResult =
testForD8()
.addProgramFiles(intermediateResult.writeToZip())
- .addMainDexListClasses(TestClass.class, A.class)
+ .addMainDexKeepClassRules(TestClass.class, A.class)
.setMinApiThreshold(parameters.getApiLevel())
.compile();
checkCompilationResult(compileResult);
diff --git a/src/test/java/com/android/tools/r8/missingclasses/MissingClassesTestBase.java b/src/test/java/com/android/tools/r8/missingclasses/MissingClassesTestBase.java
index 8dfba19..3022ea4 100644
--- a/src/test/java/com/android/tools/r8/missingclasses/MissingClassesTestBase.java
+++ b/src/test/java/com/android/tools/r8/missingclasses/MissingClassesTestBase.java
@@ -169,7 +169,7 @@
.append(" (referenced from: ")
.append(referencedFrom);
if (numberOfContexts > 1) {
- builder.append(", and ").append(numberOfContexts - 1).append(" other context");
+ builder.append(" and ").append(numberOfContexts - 1).append(" other context");
if (numberOfContexts > 2) {
builder.append("s");
}
diff --git a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
index 2811374..6a01e83 100644
--- a/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AdaptResourceFileNamesTest.java
@@ -86,6 +86,7 @@
return String.join(
System.lineSeparator(),
adaptResourceFilenamesRule,
+ "-keeppackagenames adaptresourcefilenames**",
"-keep class adaptresourcefilenames.TestClass {",
" public static void main(...);",
"}");
diff --git a/src/test/java/com/android/tools/r8/naming/AvoidRTest.java b/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
index 8feb257..4a35018 100644
--- a/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
+++ b/src/test/java/com/android/tools/r8/naming/AvoidRTest.java
@@ -47,16 +47,16 @@
JasminBuilder jasminBuilder = new JasminBuilder();
R8FullTestBuilder builder = testForR8(parameters.getBackend());
for (int i = 0; i < 4; i++) {
- jasminBuilder.addClass("TopLevel" + Integer.toString(i));
+ jasminBuilder.addClass("TopLevel" + i);
}
for (int i = 0; i < 4; i++) {
- jasminBuilder.addClass("p1/SecondLevel" + Integer.toString(i));
+ jasminBuilder.addClass("p1/SecondLevel" + i);
}
for (int i = 0; i < 4; i++) {
- jasminBuilder.addClass("p1/p2/ThirdLevel" + Integer.toString(i));
+ jasminBuilder.addClass("p1/p2/ThirdLevel" + i);
}
for (int i = 0; i < 4; i++) {
- jasminBuilder.addClass("p2/SecondLevel" + Integer.toString(i));
+ jasminBuilder.addClass("p2/SecondLevel" + i);
}
builder.addProgramClassFileData(jasminBuilder.buildClasses());
Set<String> usedDescriptors = new HashSet<>();
@@ -84,7 +84,7 @@
JasminBuilder jasminBuilder = new JasminBuilder();
R8FullTestBuilder builder = testForR8(parameters.getBackend());
for (int i = 0; i < 26 * 2; i++) {
- jasminBuilder.addClass("TestClass" + Integer.toString(i));
+ jasminBuilder.addClass("TestClass" + i);
}
builder.addProgramClassFileData(jasminBuilder.buildClasses());
Set<String> usedNames = new HashSet<>();
diff --git a/src/test/java/com/android/tools/r8/naming/ClassObfuscationDictionaryDuplicateTest.java b/src/test/java/com/android/tools/r8/naming/ClassObfuscationDictionaryDuplicateTest.java
index e0ef67d..4683db2 100644
--- a/src/test/java/com/android/tools/r8/naming/ClassObfuscationDictionaryDuplicateTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ClassObfuscationDictionaryDuplicateTest.java
@@ -5,8 +5,9 @@
package com.android.tools.r8.naming;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static junit.framework.TestCase.assertTrue;
import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.TestBase;
@@ -16,8 +17,6 @@
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import java.io.IOException;
import java.nio.file.Path;
-import java.util.HashSet;
-import java.util.Set;
import java.util.concurrent.ExecutionException;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -51,16 +50,11 @@
public void test() throws IOException, CompilationFailedException, ExecutionException {
Path dictionary = temp.getRoot().toPath().resolve("dictionary.txt");
FileUtils.writeTextFile(dictionary, "a");
-
- Set<String> finalNames = new HashSet<>();
- finalNames.add(A.class.getPackage().getName() + ".a");
- finalNames.add(B.class.getPackage().getName() + ".b");
-
testForR8(parameters.getBackend())
.addProgramClasses(A.class, B.class, C.class)
- .noTreeShaking()
.addKeepRules("-classobfuscationdictionary " + dictionary.toString())
.addKeepMainRule(C.class)
+ .addKeepClassRulesWithAllowObfuscation(A.class, B.class)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), C.class)
.assertSuccessWithOutput("HELLO WORLD!")
@@ -68,11 +62,12 @@
inspector -> {
ClassSubject clazzA = inspector.clazz(A.class);
assertThat(clazzA, isPresent());
- assertTrue(finalNames.contains(clazzA.getFinalName()));
- finalNames.remove(clazzA.getFinalName());
ClassSubject clazzB = inspector.clazz(B.class);
assertThat(clazzB, isPresent());
- assertTrue(finalNames.contains(clazzB.getFinalName()));
+ assertEquals(
+ clazzA.getDexProgramClass().type.getPackageName(),
+ clazzB.getDexProgramClass().type.getPackageName());
+ assertNotEquals(clazzA.getFinalName(), clazzB.getFinalName());
});
}
}
diff --git a/src/test/java/com/android/tools/r8/naming/DontUseMixedCaseClassNamesExistingClassTest.java b/src/test/java/com/android/tools/r8/naming/DontUseMixedCaseClassNamesExistingClassTest.java
index 6804b54..bb7e06d 100644
--- a/src/test/java/com/android/tools/r8/naming/DontUseMixedCaseClassNamesExistingClassTest.java
+++ b/src/test/java/com/android/tools/r8/naming/DontUseMixedCaseClassNamesExistingClassTest.java
@@ -50,6 +50,7 @@
.setMinApi(parameters.getApiLevel())
.addKeepClassRulesWithAllowObfuscation(A.class)
.addKeepMainRule(Main.class)
+ .addKeepPackageNamesRule(Main.class.getPackage())
.addKeepRules("-classobfuscationdictionary " + dictionary.toString())
.applyIf(dontUseMixedCase, b -> b.addKeepRules("-dontusemixedcaseclassnames"))
.run(parameters.getRuntime(), Main.class)
diff --git a/src/test/java/com/android/tools/r8/naming/KeepPackageNamesTest.java b/src/test/java/com/android/tools/r8/naming/KeepPackageNamesTest.java
index f72abf5..bb73c3f 100644
--- a/src/test/java/com/android/tools/r8/naming/KeepPackageNamesTest.java
+++ b/src/test/java/com/android/tools/r8/naming/KeepPackageNamesTest.java
@@ -10,6 +10,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import com.android.tools.r8.ProguardVersion;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.naming.keeppackagenames.Top;
@@ -47,6 +48,7 @@
assertEquals(
getPackageNameFromDescriptor(top.getOriginalDescriptor()),
getPackageNameFromDescriptor(top.getFinalDescriptor()));
+ assertEquals(PACKAGE_NAME, getPackageNameFromDescriptor(top.getFinalDescriptor()));
ClassSubject sub = inspector.clazz(SubClass.class);
assertThat(sub, isPresentAndRenamed());
@@ -55,13 +57,13 @@
assertNotEquals(
getPackageNameFromDescriptor(sub.getOriginalDescriptor()),
getPackageNameFromDescriptor(sub.getFinalDescriptor()));
- assertThat(
- getPackageNameFromDescriptor(sub.getFinalDescriptor()), containsString(PACKAGE_NAME));
break;
case DOUBLE_ASTERISKS:
assertEquals(
getPackageNameFromDescriptor(sub.getOriginalDescriptor()),
getPackageNameFromDescriptor(sub.getFinalDescriptor()));
+ assertThat(
+ getPackageNameFromDescriptor(sub.getFinalDescriptor()), containsString(PACKAGE_NAME));
break;
}
}
@@ -80,7 +82,7 @@
@Test
public void testProguard() throws Exception {
- testForProguard()
+ testForProguard(ProguardVersion.V6_0_1)
.addProgramClasses(CLASSES)
.addKeepAllClassesRuleWithAllowObfuscation()
.addKeepRules(config.getKeepRule())
diff --git a/src/test/java/com/android/tools/r8/naming/MinificationMixedCaseAndNumbersTest.java b/src/test/java/com/android/tools/r8/naming/MinificationMixedCaseAndNumbersTest.java
index f27f20f..5c050a6 100644
--- a/src/test/java/com/android/tools/r8/naming/MinificationMixedCaseAndNumbersTest.java
+++ b/src/test/java/com/android/tools/r8/naming/MinificationMixedCaseAndNumbersTest.java
@@ -34,7 +34,7 @@
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimes().build();
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
}
public MinificationMixedCaseAndNumbersTest(TestParameters parameters) {
@@ -55,8 +55,9 @@
.addInnerClasses(MinificationMixedCaseAndNumbersTest.class)
.addKeepMainRule(Main.class)
.noTreeShaking()
- .addKeepRules("-dontusemixedcaseclassnames")
- .setMinApi(parameters.getRuntime())
+ .addKeepRules(
+ "-dontusemixedcaseclassnames", "-keeppackagenames com.android.tools.r8.naming")
+ .setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
.inspect(
inspector -> {
diff --git a/src/test/java/com/android/tools/r8/naming/MinifyPackageWithKeepToPackagePrivateMemberTest.java b/src/test/java/com/android/tools/r8/naming/MinifyPackageWithKeepToPackagePrivateMemberTest.java
new file mode 100644
index 0000000..8064520
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/MinifyPackageWithKeepToPackagePrivateMemberTest.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.naming;
+
+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 MinifyPackageWithKeepToPackagePrivateMemberTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public MinifyPackageWithKeepToPackagePrivateMemberTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClassFileData(
+ transformer(A.class).removeInnerClasses().transform(),
+ transformer(ReflectiveCallerOfA.class).removeInnerClasses().transform(),
+ transformer(Main.class).removeInnerClasses().transform())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello World!", "Hello World!");
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClassFileData(
+ transformer(A.class).removeInnerClasses().transform(),
+ transformer(ReflectiveCallerOfA.class).removeInnerClasses().transform(),
+ transformer(Main.class).removeInnerClasses().transform())
+ .addKeepMainRule(Main.class)
+ .addKeepClassAndMembersRulesWithAllowObfuscation(A.class)
+ .addKeepRules("-keepclassmembernames class ** { *; }")
+ .addKeepRules(
+ "-identifiernamestring class "
+ + ReflectiveCallerOfA.class.getTypeName()
+ + " { java.lang.String className; }")
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("Hello World!", "Hello World!");
+ }
+
+ static class A {
+
+ A() {}
+
+ String foo = "Hello World!";
+
+ void foo() {
+ System.out.println("Hello World!");
+ }
+ }
+
+ public static class ReflectiveCallerOfA {
+
+ private static String className =
+ "com.android.tools.r8.naming.MinifyPackageWithKeepToPackagePrivateMemberTest$A";
+
+ @NeverInline
+ public static void callA() throws Exception {
+ Class<?> aClass = Class.forName(className);
+ Object o = aClass.getDeclaredConstructor().newInstance();
+ System.out.println(aClass.getDeclaredField("foo").get(o));
+ aClass.getDeclaredMethod("foo").invoke(o);
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) throws Exception {
+ ReflectiveCallerOfA.callA();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/MinifyPackageWithKeepToPublicMemberTest.java b/src/test/java/com/android/tools/r8/naming/MinifyPackageWithKeepToPublicMemberTest.java
new file mode 100644
index 0000000..240506d
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/naming/MinifyPackageWithKeepToPublicMemberTest.java
@@ -0,0 +1,129 @@
+// 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.naming;
+
+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 static org.junit.Assert.assertNotEquals;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+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 MinifyPackageWithKeepToPublicMemberTest extends TestBase {
+
+ private final TestParameters parameters;
+ private final boolean minify;
+ private final String[] EXPECTED = new String[] {"Hello World!", "Hello World!"};
+
+ @Parameters(name = "{0}, minifyA: {1}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withAllRuntimesAndApiLevels().build(), BooleanUtils.values());
+ }
+
+ public MinifyPackageWithKeepToPublicMemberTest(TestParameters parameters, boolean minify) {
+ this.parameters = parameters;
+ this.minify = minify;
+ }
+
+ @Test
+ public void testRuntime() throws Exception {
+ testForRuntime(parameters)
+ .addProgramClassFileData(
+ transformer(A.class).removeInnerClasses().transform(),
+ transformer(ReflectiveCallerOfA.class).removeInnerClasses().transform(),
+ transformer(Main.class).removeInnerClasses().transform())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClassFileData(
+ transformer(A.class).removeInnerClasses().transform(),
+ transformer(ReflectiveCallerOfA.class).removeInnerClasses().transform(),
+ transformer(Main.class).removeInnerClasses().transform())
+ .addKeepMainRule(Main.class)
+ .applyIf(
+ minify,
+ builder -> builder.addKeepClassAndMembersRulesWithAllowObfuscation(A.class),
+ builder -> builder.addKeepClassAndMembersRules(A.class))
+ .addKeepRules("-keepclassmembernames class ** { *; }")
+ .addKeepRules(
+ "-identifiernamestring class "
+ + ReflectiveCallerOfA.class.getTypeName()
+ + " { java.lang.String className; }")
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(
+ inspector -> {
+ ClassSubject aClazz = inspector.clazz(A.class);
+ assertThat(aClazz, isPresentAndRenamed(minify));
+ ClassSubject reflectiveCallerOfAClass = inspector.clazz(ReflectiveCallerOfA.class);
+ assertThat(reflectiveCallerOfAClass, isPresentAndRenamed());
+ ClassSubject mainClass = inspector.clazz(Main.class);
+ assertThat(mainClass, isPresentAndNotRenamed());
+ assertNotEquals(
+ mainClass.getDexProgramClass().type.getPackageDescriptor(),
+ reflectiveCallerOfAClass.getDexProgramClass().type.getPackageDescriptor());
+ if (minify) {
+ assertEquals(
+ aClazz.getDexProgramClass().type.getPackageDescriptor(),
+ reflectiveCallerOfAClass.getDexProgramClass().type.getPackageDescriptor());
+ } else {
+ assertNotEquals(
+ aClazz.getDexProgramClass().type.getPackageDescriptor(),
+ reflectiveCallerOfAClass.getDexProgramClass().type.getPackageDescriptor());
+ }
+ })
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ public static class A {
+
+ public A() {}
+
+ public String foo = "Hello World!";
+
+ public void foo() {
+ System.out.println("Hello World!");
+ }
+ }
+
+ public static class ReflectiveCallerOfA {
+
+ private static String className =
+ "com.android.tools.r8.naming.MinifyPackageWithKeepToPublicMemberTest$A";
+
+ @NeverInline
+ public static void callA() throws Exception {
+ Class<?> aClass = Class.forName(className);
+ Object o = aClass.getDeclaredConstructor().newInstance();
+ System.out.println(aClass.getDeclaredField("foo").get(o));
+ aClass.getDeclaredMethod("foo").invoke(o);
+ }
+ }
+
+ public static class Main {
+
+ public static void main(String[] args) throws Exception {
+ ReflectiveCallerOfA.callA();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java b/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
index 66ec3bb..9079f61 100644
--- a/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/PackageNamingTest.java
@@ -238,9 +238,9 @@
b.getDexProgramClass().getType().getPackageName());
ClassSubject sub_a = inspector.clazz("naming044.sub.SubA");
- assertEquals(2, countPackageDepth(sub_a));
+ assertEquals(1, countPackageDepth(sub_a));
ClassSubject sub_b = inspector.clazz("naming044.sub.SubB");
- assertEquals(2, countPackageDepth(sub_b));
+ assertEquals(1, countPackageDepth(sub_b));
assertEquals(
sub_a.getDexProgramClass().getType().getPackageName(),
sub_b.getDexProgramClass().getType().getPackageName());
@@ -327,9 +327,9 @@
// All packages are renamed somehow. Need to check package hierarchy is consistent.
ClassSubject aa = inspector.clazz("naming101.a.a");
- assertEquals(2, countPackageDepth(aa));
+ assertEquals(1, countPackageDepth(aa));
ClassSubject abc = inspector.clazz("naming101.a.b.c");
- assertEquals(3, countPackageDepth(abc));
+ assertEquals(1, countPackageDepth(abc));
// naming101.a/a; -> La/a/a; --prefix--> La/a
// naming101.a/b/c; -> La/a/a/a; --prefix--> La/a/a --prefix--> La/a
@@ -356,14 +356,20 @@
ba.getDexProgramClass().getType().getPackageName(),
bb.getDexProgramClass().getType().getPackageName());
- // All other classes can be repackaged to naming101.a, but naming101.a.a exists to make a name
- // conflict. Thus, those should not be renamed to 'a'.
- List<String> klasses = ImmutableList.of("naming101.c", "naming101.d", "naming101.a.b.c");
+ // We cannot repackage c or d since these have package-private members and a
+ // keep,allowobfuscation. For us to be able to repackage them, we have to use
+ // -allowaccesmodification.
+ List<String> klasses = ImmutableList.of("naming101.c", "naming101.d");
for (String klass : klasses) {
ClassSubject k = inspector.clazz(klass);
- assertEquals("naming101.a", k.getDexProgramClass().getType().getPackageName());
- assertNotEquals("naming101.a.a", k.getFinalName());
+ assertNotEquals("naming101.a", k.getDexProgramClass().getType().getPackageName());
}
+
+ // All other classes can be repackaged to naming101.a, but naming101.a.a exists to make a name
+ // conflict. Thus, those should not be renamed to 'a'.
+ ClassSubject namingAbc = inspector.clazz("naming101.a.b.c");
+ assertEquals("naming101.a", namingAbc.getDexProgramClass().getType().getPackageName());
+ assertNotEquals("naming101.a.a", namingAbc.getFinalName());
}
private static void test101_rule104(CodeInspector inspector) {
@@ -411,11 +417,12 @@
ClassSubject topD = inspector.clazz("naming101.d");
assertEquals("naming101", topD.getDexProgramClass().getType().getPackageName());
- // Due to the keep rule for naming101.c, package prefix naming101 is reserved.
- // That is, every renamed class should have naming101 as parent package prefix.
- for (String klass : klasses) {
- ClassSubject t = inspector.clazz(klass);
- assertTrue(t.getFinalName().startsWith("naming101."));
- }
+ // The remaining classes are in subpackages of naming101 and will therefore not have
+ // package-private access to namin101.c
+ ClassSubject subAC = inspector.clazz("naming101.a.c");
+ assertEquals(1, countPackageDepth(subAC));
+
+ ClassSubject subABC = inspector.clazz("naming101.a.b.c");
+ assertEquals(1, countPackageDepth(subABC));
}
}
diff --git a/src/test/java/com/android/tools/r8/naming/PackageObfuscationDictionaryDuplicateTest.java b/src/test/java/com/android/tools/r8/naming/PackageObfuscationDictionaryDuplicateTest.java
index 133e607..0ac480f 100644
--- a/src/test/java/com/android/tools/r8/naming/PackageObfuscationDictionaryDuplicateTest.java
+++ b/src/test/java/com/android/tools/r8/naming/PackageObfuscationDictionaryDuplicateTest.java
@@ -57,9 +57,9 @@
.inspect(
inspector -> {
ClassSubject clazzTop = inspector.clazz(Top.class);
- assertTrue(clazzTop.getFinalName().endsWith(".a.a"));
+ assertTrue(clazzTop.getFinalName().endsWith("a.a"));
ClassSubject clazzA = inspector.clazz(A.class);
- assertTrue(clazzA.getFinalName().endsWith(".b.a"));
+ assertTrue(clazzA.getFinalName().endsWith("b.a"));
});
}
}
diff --git a/src/test/java/com/android/tools/r8/naming/PackagePrivateAllowAccessModificationPackageTest.java b/src/test/java/com/android/tools/r8/naming/PackagePrivateAllowAccessModificationPackageTest.java
index 473df64..4be6559 100644
--- a/src/test/java/com/android/tools/r8/naming/PackagePrivateAllowAccessModificationPackageTest.java
+++ b/src/test/java/com/android/tools/r8/naming/PackagePrivateAllowAccessModificationPackageTest.java
@@ -53,10 +53,6 @@
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
- .addOptionsModification(
- options -> {
- options.enablePackagePrivateAwarePublicization = true;
- })
.compile()
.inspect(
inspector -> {
@@ -64,8 +60,7 @@
assertThat(clazz, isPresentAndRenamed());
})
.run(parameters.getRuntime(), Main.class)
- // TODO(b/172496438): This should not fail.
- .assertFailureWithErrorThatThrows(IllegalAccessError.class);
+ .assertSuccessWithOutputLines(EXPECTED);
}
@NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/naming/b139991218/TestRunner.java b/src/test/java/com/android/tools/r8/naming/b139991218/TestRunner.java
index 10ce37d..d9b9a3c 100644
--- a/src/test/java/com/android/tools/r8/naming/b139991218/TestRunner.java
+++ b/src/test/java/com/android/tools/r8/naming/b139991218/TestRunner.java
@@ -10,15 +10,15 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.TestBase;
+import com.android.tools.r8.KotlinCompilerTool;
+import com.android.tools.r8.KotlinTestBase;
+import com.android.tools.r8.KotlinTestParameters;
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.ir.optimize.Inliner.Reason;
-import com.android.tools.r8.utils.FileUtils;
import com.google.common.collect.ImmutableSet;
import java.io.IOException;
-import java.nio.file.Paths;
+import java.util.List;
import java.util.concurrent.ExecutionException;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -33,16 +33,26 @@
* which is why the ASMified code is generated from kotlin.
*/
@RunWith(Parameterized.class)
-public class TestRunner extends TestBase {
+public class TestRunner extends KotlinTestBase {
private final TestParameters parameters;
+ private static final KotlinCompileMemoizer kotlinJars =
+ getCompileMemoizer(getKotlinFilesInResource("lambdas_kstyle_generics"))
+ .configure(KotlinCompilerTool::includeRuntime);
+
@Parameters(name = "{0}")
- public static TestParametersCollection data() {
- return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ public static List<Object[]> data() {
+ return buildParameters(
+ getTestParameters().withDexRuntimes().withAllApiLevels().build(),
+ getKotlinTestParameters()
+ .withAllCompilers()
+ .withTargetVersion(KotlinTargetVersion.JAVA_8)
+ .build());
}
- public TestRunner(TestParameters parameters) {
+ public TestRunner(TestParameters parameters, KotlinTestParameters kotlinParameters) {
+ super(kotlinParameters);
this.parameters = parameters;
}
@@ -52,12 +62,7 @@
testForR8(parameters.getBackend())
.addProgramClassFileData(Lambda1.dump(), Lambda2.dump(), Main.dump(), Alpha.dump())
.addProgramFiles(
- Paths.get(
- ToolHelper.TESTS_BUILD_DIR,
- "kotlinR8TestResources",
- "JAVA_8",
- "lambdas_kstyle_generics" + FileUtils.JAR_EXTENSION),
- getMostRecentKotlinAnnotationJar())
+ kotlinJars.getForConfiguration(kotlinParameters), getMostRecentKotlinAnnotationJar())
.addKeepMainRule(Main.class)
.addKeepAllAttributes()
.addOptionsModification(
diff --git a/src/test/java/com/android/tools/r8/naming/b155249069/DontUseMixedCaseClassNamesExistingClassPackageTest.java b/src/test/java/com/android/tools/r8/naming/b155249069/DontUseMixedCaseClassNamesExistingClassPackageTest.java
index f662aa6..696704f 100644
--- a/src/test/java/com/android/tools/r8/naming/b155249069/DontUseMixedCaseClassNamesExistingClassPackageTest.java
+++ b/src/test/java/com/android/tools/r8/naming/b155249069/DontUseMixedCaseClassNamesExistingClassPackageTest.java
@@ -12,6 +12,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.naming.b155249069.package_b.A;
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 java.io.IOException;
@@ -29,6 +30,8 @@
private final TestParameters parameters;
private final boolean dontUseMixedCase;
+ private final String renamedATypeName = "Testpackage.A";
+
@Parameters(name = "{0}, dontusemixedcaseclassnames: {1}")
public static List<Object[]> data() {
return buildParameters(
@@ -45,12 +48,22 @@
public void testR8() throws ExecutionException, CompilationFailedException, IOException {
Path packageDictionary = temp.getRoot().toPath().resolve("packagedictionary.txt");
// Suggest the name 'a' for the package, to force a collision with A.A.
- FileUtils.writeTextFile(packageDictionary, "a");
+ FileUtils.writeTextFile(packageDictionary, "testpackage");
testForR8(parameters.getBackend())
- .addProgramClasses(Main.class, com.android.tools.r8.naming.b155249069.A.A.class, A.class)
+ .addProgramClasses(A.class)
+ .addProgramClassFileData(
+ transformer(Main.class)
+ .replaceClassDescriptorInMethodInstructions(
+ DescriptorUtils.javaTypeToDescriptor(
+ com.android.tools.r8.naming.b155249069.A.A.class.getTypeName()),
+ DescriptorUtils.javaTypeToDescriptor(renamedATypeName))
+ .transform(),
+ transformer(com.android.tools.r8.naming.b155249069.A.A.class)
+ .setClassDescriptor(DescriptorUtils.javaTypeToDescriptor(renamedATypeName))
+ .transform())
.setMinApi(parameters.getApiLevel())
- // Keep A.A such that the package A is kept.
- .addKeepClassRules(com.android.tools.r8.naming.b155249069.A.A.class)
+ // Keep testpackage.A such that the package A is kept.
+ .addKeepClassRules(renamedATypeName)
.addKeepClassRulesWithAllowObfuscation(A.class)
.addKeepMainRule(Main.class)
.addKeepRules("-packageobfuscationdictionary " + packageDictionary.toString())
@@ -59,8 +72,7 @@
.assertSuccessWithOutputLines("A.A.foo()", "package_b.B.foo()")
.inspect(
inspector -> {
- ClassSubject aSubject =
- inspector.clazz(com.android.tools.r8.naming.b155249069.A.A.class);
+ ClassSubject aSubject = inspector.clazz(renamedATypeName);
ClassSubject bSubject = inspector.clazz(A.class);
if (dontUseMixedCase) {
assertNotEquals(
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java
index 63201fa..df0bfa6 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageLambdaMissingInterfaceTest.java
@@ -4,12 +4,14 @@
package com.android.tools.r8.repackage;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresentAndRenamed;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -50,12 +52,16 @@
.inspect(
inspector -> {
// Find the generated lambda class
- assertThat(
- ClassWithLambda.class,
- isRepackagedIf(inspector, repackage && parameters.isDexRuntime()));
if (!parameters.isDexRuntime()) {
+ assertThat(ClassWithLambda.class, isNotRepackaged(inspector));
return;
}
+ if (repackage) {
+ assertThat(ClassWithLambda.class, isRepackaged(inspector));
+ } else {
+ ClassSubject classWithLambdaSubject = inspector.clazz(ClassWithLambda.class);
+ assertThat(classWithLambdaSubject, isPresentAndRenamed());
+ }
inspector.forAllClasses(
clazz -> {
if (clazz.isSynthesizedJavaLambdaClass()) {
diff --git a/src/test/java/com/android/tools/r8/shaking/MissingInterfaceTest.java b/src/test/java/com/android/tools/r8/shaking/MissingInterfaceTest.java
index 617676f..c5c0859 100644
--- a/src/test/java/com/android/tools/r8/shaking/MissingInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/MissingInterfaceTest.java
@@ -24,7 +24,7 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimesAndApiLevels().build();
+ return getTestParameters().withDexRuntimes().withAllApiLevels().build();
}
public MissingInterfaceTest(TestParameters parameters) {
@@ -39,6 +39,7 @@
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(TestClassForB112849320.class)
.addOptionsModification(options -> options.enableInlining = false)
+ .addKeepPackageNamesRule(GoingToBeMissed.class.getPackage())
.compile()
.addRunClasspathFiles(
buildOnDexRuntime(
diff --git a/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java b/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java
index b0e1ab2..5492f54 100644
--- a/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java
+++ b/src/test/java/com/android/tools/r8/testing/ToolHelperTest.java
@@ -30,7 +30,9 @@
ToolHelper.getFirstSupportedAndroidJar(AndroidApiLevel.K_WATCH), AndroidApiLevel.L);
// All android.jar's for API level L are present.
for (AndroidApiLevel androidApiLevel : AndroidApiLevel.values()) {
- if (androidApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.L)) {
+ // TODO(b/181356260): Add AndroidJar for S.
+ if (androidApiLevel.isGreaterThanOrEqualTo(AndroidApiLevel.L)
+ && androidApiLevel.isLessThan(AndroidApiLevel.S)) {
checkExpectedAndroidJar(
ToolHelper.getFirstSupportedAndroidJar(androidApiLevel), androidApiLevel);
}
diff --git a/src/test/examplesKotlin/enumswitch/EnumSwitch.kt b/src/test/kotlinR8TestResources/enumswitch/EnumSwitch.kt
similarity index 100%
rename from src/test/examplesKotlin/enumswitch/EnumSwitch.kt
rename to src/test/kotlinR8TestResources/enumswitch/EnumSwitch.kt
diff --git a/src/test/examplesKotlin/loops/Loop.kt b/src/test/kotlinR8TestResources/loops/Loop.kt
similarity index 100%
rename from src/test/examplesKotlin/loops/Loop.kt
rename to src/test/kotlinR8TestResources/loops/Loop.kt
diff --git a/third_party/openjdk/desugar_jdk_libs.tar.gz.sha1 b/third_party/openjdk/desugar_jdk_libs.tar.gz.sha1
index 5b0c632..c53b59b 100644
--- a/third_party/openjdk/desugar_jdk_libs.tar.gz.sha1
+++ b/third_party/openjdk/desugar_jdk_libs.tar.gz.sha1
@@ -1 +1 @@
-babe03fe1d812b8eddebfc3e9a1ea4add98d4647
\ No newline at end of file
+2e91f1ecbf04376cd0d8a9bd27615aa399f374c1
\ No newline at end of file
diff --git a/tools/r8_release.py b/tools/r8_release.py
index d356586..72a5e02 100755
--- a/tools/r8_release.py
+++ b/tools/r8_release.py
@@ -163,7 +163,8 @@
def update_prebuilds(r8_checkout, version, checkout):
path = os.path.join(r8_checkout, 'tools', 'update_prebuilds_in_android.py')
- subprocess.check_call([path, '--targets=lib', '--maps', '--version=' + version, checkout])
+ commit_arg = '--commit_hash=' if len(version) == 40 else '--version='
+ subprocess.check_call([path, '--targets=lib', '--maps', commit_arg + version, checkout])
def release_studio_or_aosp(r8_checkout, path, options, git_message):