Merge "Allow storing arbitrary class types in fields with an interface type"
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index 61161bb..48c2cde 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -4,12 +4,12 @@
package com.android.tools.r8;
import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexDefinition;
import com.android.tools.r8.graph.GraphLense;
-import com.android.tools.r8.graphinfo.GraphConsumer;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.android.tools.r8.shaking.MainDexClasses;
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexListCommand.java b/src/main/java/com/android/tools/r8/GenerateMainDexListCommand.java
index a1a2837..a55033a 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexListCommand.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexListCommand.java
@@ -3,8 +3,8 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8;
+import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graphinfo.GraphConsumer;
import com.android.tools.r8.origin.CommandLineOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.ProguardConfigurationParser;
diff --git a/src/main/java/com/android/tools/r8/KeepSubclassesForCodeGeneration.java b/src/main/java/com/android/tools/r8/KeepSubclassesForCodeGeneration.java
new file mode 100644
index 0000000..5f20584
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/KeepSubclassesForCodeGeneration.java
@@ -0,0 +1,7 @@
+// 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;
+
+@Keep
+public @interface KeepSubclassesForCodeGeneration {}
diff --git a/src/main/java/com/android/tools/r8/PrintUses.java b/src/main/java/com/android/tools/r8/PrintUses.java
index 3687f23..d5f0156 100644
--- a/src/main/java/com/android/tools/r8/PrintUses.java
+++ b/src/main/java/com/android/tools/r8/PrintUses.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.graph.AppInfo.ResolutionResult;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
+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.DexEncodedField;
@@ -15,6 +16,9 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.DexValue.DexValueArray;
+import com.android.tools.r8.graph.DexValue.DexValueType;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
@@ -115,13 +119,13 @@
@Override
public boolean registerInstanceFieldWrite(DexField field) {
- addField(field);
+ addField(field, false);
return false;
}
@Override
public boolean registerInstanceFieldRead(DexField field) {
- addField(field);
+ addField(field, false);
return false;
}
@@ -133,13 +137,13 @@
@Override
public boolean registerStaticFieldRead(DexField field) {
- addField(field);
+ addField(field, true);
return false;
}
@Override
public boolean registerStaticFieldWrite(DexField field) {
- addField(field);
+ addField(field, true);
return false;
}
@@ -160,8 +164,15 @@
return descriptors.contains(type.toDescriptorString());
}
- private void addField(DexField field) {
+ private void addField(DexField field, boolean isStatic) {
addType(field.type);
+ DexEncodedField baseField =
+ isStatic
+ ? appInfo.lookupStaticTarget(field.clazz, field)
+ : appInfo.lookupInstanceTarget(field.clazz, field);
+ if (baseField != null && baseField.field.clazz != field.clazz) {
+ field = baseField.field;
+ }
addType(field.clazz);
Set<DexField> typeFields = fields.get(field.clazz);
if (typeFields != null) {
@@ -193,6 +204,14 @@
for (DexType type : method.method.proto.parameters.values) {
registerTypeReference(type);
}
+ for (DexAnnotation annotation : method.annotations.annotations) {
+ if (annotation.annotation.type == appInfo.dexItemFactory.annotationThrows) {
+ DexValueArray dexValues = (DexValueArray) annotation.annotation.elements[0].value;
+ for (DexValue dexValType : dexValues.getValues()) {
+ registerTypeReference(((DexValueType) dexValType).value);
+ }
+ }
+ }
registerTypeReference(method.method.proto.returnType);
method.registerCodeReferences(this);
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 5c82a50..c1664a6 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.dex.Marker.Tool;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
@@ -19,7 +20,6 @@
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLense;
-import com.android.tools.r8.graphinfo.GraphConsumer;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.optimize.EnumOrdinalMapCollector;
import com.android.tools.r8.ir.optimize.MethodPoolCollection;
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index e533101..39630f3 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -5,8 +5,8 @@
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.errors.DexFileOverflowDiagnostic;
+import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graphinfo.GraphConsumer;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
import com.android.tools.r8.origin.StandardOutOrigin;
diff --git a/src/main/java/com/android/tools/r8/graphinfo/AnnotationGraphNode.java b/src/main/java/com/android/tools/r8/experimental/graphinfo/AnnotationGraphNode.java
similarity index 94%
rename from src/main/java/com/android/tools/r8/graphinfo/AnnotationGraphNode.java
rename to src/main/java/com/android/tools/r8/experimental/graphinfo/AnnotationGraphNode.java
index c317293..5242510 100644
--- a/src/main/java/com/android/tools/r8/graphinfo/AnnotationGraphNode.java
+++ b/src/main/java/com/android/tools/r8/experimental/graphinfo/AnnotationGraphNode.java
@@ -1,7 +1,7 @@
// 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.graphinfo;
+package com.android.tools.r8.experimental.graphinfo;
import com.android.tools.r8.Keep;
diff --git a/src/main/java/com/android/tools/r8/graphinfo/ClassGraphNode.java b/src/main/java/com/android/tools/r8/experimental/graphinfo/ClassGraphNode.java
similarity index 94%
rename from src/main/java/com/android/tools/r8/graphinfo/ClassGraphNode.java
rename to src/main/java/com/android/tools/r8/experimental/graphinfo/ClassGraphNode.java
index 41bd498..edbffbe 100644
--- a/src/main/java/com/android/tools/r8/graphinfo/ClassGraphNode.java
+++ b/src/main/java/com/android/tools/r8/experimental/graphinfo/ClassGraphNode.java
@@ -1,7 +1,7 @@
// 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.graphinfo;
+package com.android.tools.r8.experimental.graphinfo;
import com.android.tools.r8.Keep;
import com.android.tools.r8.references.ClassReference;
diff --git a/src/main/java/com/android/tools/r8/graphinfo/FieldGraphNode.java b/src/main/java/com/android/tools/r8/experimental/graphinfo/FieldGraphNode.java
similarity index 94%
rename from src/main/java/com/android/tools/r8/graphinfo/FieldGraphNode.java
rename to src/main/java/com/android/tools/r8/experimental/graphinfo/FieldGraphNode.java
index 9ae9a5b..b091613 100644
--- a/src/main/java/com/android/tools/r8/graphinfo/FieldGraphNode.java
+++ b/src/main/java/com/android/tools/r8/experimental/graphinfo/FieldGraphNode.java
@@ -1,7 +1,7 @@
// 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.graphinfo;
+package com.android.tools.r8.experimental.graphinfo;
import com.android.tools.r8.Keep;
import com.android.tools.r8.references.FieldReference;
diff --git a/src/main/java/com/android/tools/r8/graphinfo/GraphConsumer.java b/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphConsumer.java
similarity index 91%
rename from src/main/java/com/android/tools/r8/graphinfo/GraphConsumer.java
rename to src/main/java/com/android/tools/r8/experimental/graphinfo/GraphConsumer.java
index 8c124e5..3c7bda1 100644
--- a/src/main/java/com/android/tools/r8/graphinfo/GraphConsumer.java
+++ b/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphConsumer.java
@@ -1,7 +1,7 @@
// 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.graphinfo;
+package com.android.tools.r8.experimental.graphinfo;
import com.android.tools.r8.KeepForSubclassing;
diff --git a/src/main/java/com/android/tools/r8/graphinfo/GraphEdgeInfo.java b/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphEdgeInfo.java
similarity index 95%
rename from src/main/java/com/android/tools/r8/graphinfo/GraphEdgeInfo.java
rename to src/main/java/com/android/tools/r8/experimental/graphinfo/GraphEdgeInfo.java
index c0b3f3b..0c838ac 100644
--- a/src/main/java/com/android/tools/r8/graphinfo/GraphEdgeInfo.java
+++ b/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphEdgeInfo.java
@@ -1,7 +1,7 @@
// 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.graphinfo;
+package com.android.tools.r8.experimental.graphinfo;
public class GraphEdgeInfo {
diff --git a/src/main/java/com/android/tools/r8/graphinfo/GraphNode.java b/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphNode.java
similarity index 92%
rename from src/main/java/com/android/tools/r8/graphinfo/GraphNode.java
rename to src/main/java/com/android/tools/r8/experimental/graphinfo/GraphNode.java
index f248978..b99485a 100644
--- a/src/main/java/com/android/tools/r8/graphinfo/GraphNode.java
+++ b/src/main/java/com/android/tools/r8/experimental/graphinfo/GraphNode.java
@@ -1,7 +1,7 @@
// 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.graphinfo;
+package com.android.tools.r8.experimental.graphinfo;
import com.android.tools.r8.Keep;
diff --git a/src/main/java/com/android/tools/r8/graphinfo/KeepRuleGraphNode.java b/src/main/java/com/android/tools/r8/experimental/graphinfo/KeepRuleGraphNode.java
similarity index 97%
rename from src/main/java/com/android/tools/r8/graphinfo/KeepRuleGraphNode.java
rename to src/main/java/com/android/tools/r8/experimental/graphinfo/KeepRuleGraphNode.java
index 05a6e3d..7eb55a8 100644
--- a/src/main/java/com/android/tools/r8/graphinfo/KeepRuleGraphNode.java
+++ b/src/main/java/com/android/tools/r8/experimental/graphinfo/KeepRuleGraphNode.java
@@ -1,7 +1,7 @@
// 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.graphinfo;
+package com.android.tools.r8.experimental.graphinfo;
import com.android.tools.r8.Keep;
import com.android.tools.r8.origin.Origin;
diff --git a/src/main/java/com/android/tools/r8/graphinfo/MethodGraphNode.java b/src/main/java/com/android/tools/r8/experimental/graphinfo/MethodGraphNode.java
similarity index 94%
rename from src/main/java/com/android/tools/r8/graphinfo/MethodGraphNode.java
rename to src/main/java/com/android/tools/r8/experimental/graphinfo/MethodGraphNode.java
index 494ddd4..94fe8e7 100644
--- a/src/main/java/com/android/tools/r8/graphinfo/MethodGraphNode.java
+++ b/src/main/java/com/android/tools/r8/experimental/graphinfo/MethodGraphNode.java
@@ -1,7 +1,7 @@
// 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.graphinfo;
+package com.android.tools.r8.experimental.graphinfo;
import com.android.tools.r8.Keep;
import com.android.tools.r8.references.MethodReference;
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index f69251b..c76865e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -482,6 +482,12 @@
enclosingMethod = null;
}
+ public void removeEnclosingMethod(Predicate<EnclosingMethodAttribute> predicate) {
+ if (enclosingMethod != null && predicate.test(enclosingMethod)) {
+ enclosingMethod = null;
+ }
+ }
+
public void clearInnerClasses() {
innerClasses.clear();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index e4f1c8c..012c4a4 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -7,6 +7,7 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.ProgramResourceProvider;
+import com.android.tools.r8.graph.LazyLoadedDexApplication.AllClasses;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.ProgramClassCollection;
import com.android.tools.r8.utils.Timing;
@@ -21,9 +22,11 @@
public class DirectMappedDexApplication extends DexApplication {
+ private final AllClasses allClasses;
private final ImmutableMap<DexType, DexLibraryClass> libraryClasses;
private DirectMappedDexApplication(ClassNameMapper proguardMap,
+ AllClasses allClasses,
ProgramClassCollection programClasses,
ImmutableList<ProgramResourceProvider> programResourceProviders,
ImmutableMap<DexType, DexLibraryClass> libraryClasses,
@@ -32,6 +35,7 @@
Timing timing) {
super(proguardMap, programClasses, programResourceProviders, mainDexList, deadCode,
dexItemFactory, highestSortingString, timing);
+ this.allClasses = allClasses;
this.libraryClasses = libraryClasses;
}
@@ -92,17 +96,21 @@
public static class Builder extends DexApplication.Builder<Builder> {
+ private final AllClasses allClasses;
private final List<DexLibraryClass> libraryClasses = new ArrayList<>();
Builder(LazyLoadedDexApplication application) {
super(application);
// As a side-effect, this will force-load all classes.
- Map<DexType, DexClass> allClasses = application.getFullClassMap();
+ this.allClasses = application.loadAllClasses();
+ Map<DexType, DexClass> allClasses = this.allClasses.getClasses();
+ // TODO(120884788): This filter will only add library classes which are not program classes.
Iterables.filter(allClasses.values(), DexLibraryClass.class).forEach(libraryClasses::add);
}
private Builder(DirectMappedDexApplication application) {
super(application);
+ this.allClasses = application.allClasses;
this.libraryClasses.addAll(application.libraryClasses.values());
}
@@ -116,6 +124,7 @@
// Rebuild the map. This will fail if keys are not unique.
return new DirectMappedDexApplication(
proguardMap,
+ allClasses,
ProgramClassCollection.create(
programClasses, ProgramClassCollection::resolveClassConflictImpl),
ImmutableList.copyOf(programResourceProviders),
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
index b648e41..6dea825 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -55,31 +55,67 @@
return clazz;
}
- private Map<DexType, DexClass> forceLoadAllClasses() {
- Map<DexType, DexClass> loaded = new IdentityHashMap<>();
+ static class AllClasses {
+ private Map<DexType, DexClass> libraryClasses;
+ private Map<DexType, DexClass> classpathClasses;
+ private Map<DexType, DexClass> programClasses;
+ private Map<DexType, DexClass> classes;
- // Program classes are supposed to be loaded, but force-loading them is no-op.
- programClasses.forceLoad(type -> true);
- programClasses.getAllClasses().forEach(clazz -> loaded.put(clazz.type, clazz));
+ AllClasses(
+ LibraryClassCollection libraryClasses,
+ ClasspathClassCollection classpathClasses,
+ ProgramClassCollection programClasses) {
+ load(libraryClasses, classpathClasses, programClasses);
- if (classpathClasses != null) {
- classpathClasses.forceLoad(type -> !loaded.containsKey(type));
- classpathClasses.getAllClasses().forEach(clazz -> loaded.putIfAbsent(clazz.type, clazz));
+ // Collect loaded classes in the precedence order program classes, class path classes and
+ // library classes.
+ // TODO(b/120884788): Change this.
+ classes = new IdentityHashMap<>();
+ classes.putAll(this.programClasses);
+ if (classpathClasses != null) {
+ classpathClasses.getAllClasses().forEach(clazz -> classes.putIfAbsent(clazz.type, clazz));
+ }
+ if (libraryClasses != null) {
+ libraryClasses.getAllClasses().forEach(clazz -> classes.putIfAbsent(clazz.type, clazz));
+ }
}
- if (libraryClasses != null) {
- libraryClasses.forceLoad(type -> !loaded.containsKey(type));
- libraryClasses.getAllClasses().forEach(clazz -> loaded.putIfAbsent(clazz.type, clazz));
+ public Map<DexType, DexClass> getLibraryClasses() {
+ return libraryClasses;
}
- return loaded;
+ public Map<DexType, DexClass> getClasspathClasses() {
+ return classpathClasses;
+ }
+
+ public Map<DexType, DexClass> getClasses() {
+ return classes;
+ }
+
+ private void load(
+ LibraryClassCollection libraryClasses,
+ ClasspathClassCollection classpathClasses,
+ ProgramClassCollection programClasses) {
+ if (libraryClasses != null) {
+ libraryClasses.forceLoad(type -> true);
+ this.libraryClasses = libraryClasses.getAllClassesInMap();
+ }
+ if (classpathClasses != null) {
+ classpathClasses.forceLoad(type -> true);
+ this.classpathClasses = classpathClasses.getAllClassesInMap();
+ }
+ assert programClasses != null;
+ // Program classes are supposed to be loaded, but force-loading them is no-op.
+ programClasses.forceLoad(type -> true);
+ this.programClasses = programClasses.getAllClassesInMap();
+ }
}
/**
* Force load all classes and return type -> class map containing all the classes.
*/
- public Map<DexType, DexClass> getFullClassMap() {
- return forceLoadAllClasses();
+ public AllClasses loadAllClasses() {
+ return new AllClasses(libraryClasses, classpathClasses, programClasses);
}
public static class Builder extends DexApplication.Builder<Builder> {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
index 0434f66..6ee0f6e 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRConverter.java
@@ -41,6 +41,7 @@
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.desugar.CovariantReturnTypeAnnotationTransformer;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
+import com.android.tools.r8.ir.desugar.Java8MethodRewriter;
import com.android.tools.r8.ir.desugar.LambdaRewriter;
import com.android.tools.r8.ir.desugar.StringConcatRewriter;
import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
@@ -119,6 +120,7 @@
private final LambdaRewriter lambdaRewriter;
private final InterfaceMethodRewriter interfaceMethodRewriter;
private final TwrCloseResourceRewriter twrCloseResourceRewriter;
+ private final Java8MethodRewriter java8MethodRewriter;
private final LambdaMerger lambdaMerger;
private final ClassInliner classInliner;
private final ClassStaticizer classStaticizer;
@@ -183,6 +185,8 @@
this.twrCloseResourceRewriter =
(options.enableDesugaring && enableTwrCloseResourceDesugaring())
? new TwrCloseResourceRewriter(this) : null;
+ this.java8MethodRewriter =
+ options.enableDesugaring ? new Java8MethodRewriter(this) : null;
this.lambdaMerger =
options.enableLambdaMerging ? new LambdaMerger(appInfo, options.reporter) : null;
this.covariantReturnTypeAnnotationTransformer =
@@ -367,6 +371,12 @@
}
}
+ private void synthesizeJava8UtilityClass(Builder<?> builder) {
+ if (java8MethodRewriter != null) {
+ java8MethodRewriter.synthesizeUtilityClass(builder, options);
+ }
+ }
+
private void processCovariantReturnTypeAnnotations(Builder<?> builder) {
if (covariantReturnTypeAnnotationTransformer != null) {
covariantReturnTypeAnnotationTransformer.process(builder);
@@ -387,6 +397,7 @@
synthesizeLambdaClasses(builder, executor);
desugarInterfaceMethods(builder, ExcludeDexResources, executor);
synthesizeTwrCloseResourceUtilityClass(builder);
+ synthesizeJava8UtilityClass(builder);
processCovariantReturnTypeAnnotations(builder);
handleSynthesizedClassMapping(builder);
@@ -573,11 +584,10 @@
printPhase("Interface method desugaring");
desugarInterfaceMethods(builder, IncludeAllResources, executorService);
-
printPhase("Twr close resource utility class synthesis");
synthesizeTwrCloseResourceUtilityClass(builder);
+ synthesizeJava8UtilityClass(builder);
handleSynthesizedClassMapping(builder);
-
printPhase("Lambda merging finalization");
finalizeLambdaMerging(application, feedback, builder, executorService);
@@ -1010,6 +1020,9 @@
if (options.enableDesugaring && enableTryWithResourcesDesugaring()) {
codeRewriter.rewriteThrowableAddAndGetSuppressed(code);
}
+ if (java8MethodRewriter != null) {
+ java8MethodRewriter.desugar(code);
+ }
stringConcatRewriter.desugarStringConcats(method.method, code);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
new file mode 100644
index 0000000..ea1d2c6
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
@@ -0,0 +1,496 @@
+// 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.ir.desugar;
+
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.ClassAccessFlags;
+import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexApplication.Builder;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.code.Instruction;
+import com.android.tools.r8.ir.code.InstructionIterator;
+import com.android.tools.r8.ir.code.InvokeStatic;
+import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.desugar.Java8MethodRewriter.RewritableMethods.MethodGenerator;
+import com.android.tools.r8.ir.synthetic.TemplateMethodCode;
+import com.android.tools.r8.origin.SynthesizedOrigin;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiFunction;
+
+public final class Java8MethodRewriter {
+ private static final String UTILITY_CLASS_DESCRIPTOR_PREFIX = "L$r8$java8methods$utility";
+ private final Set<DexType> holders = Sets.newConcurrentHashSet();
+ private final IRConverter converter;
+ private final DexItemFactory factory;
+ private final RewritableMethods rewritableMethods;
+
+ private Map<DexMethod, MethodGenerator> methodGenerators = new ConcurrentHashMap<>();
+
+ public Java8MethodRewriter(IRConverter converter) {
+ this.converter = converter;
+ this.factory = converter.appInfo.dexItemFactory;
+ this.rewritableMethods = new RewritableMethods(factory);
+ }
+
+ public void desugar(IRCode code) {
+ InstructionIterator iterator = code.instructionIterator();
+ while (iterator.hasNext()) {
+ Instruction instruction = iterator.next();
+ if (!instruction.isInvokeStatic()) {
+ continue;
+ }
+ InvokeStatic invoke = instruction.asInvokeStatic();
+
+ MethodGenerator generator = getMethodGeneratorOrNull(converter, invoke.getInvokedMethod());
+ if (generator == null) {
+ continue;
+ }
+ iterator.replaceCurrentInstruction(
+ new InvokeStatic(generator.generateMethod(factory),
+ invoke.outValue(), invoke.inValues()));
+ methodGenerators.putIfAbsent(generator.generateMethod(factory), generator);
+ holders.add(code.method.method.holder);
+ }
+ }
+
+ private Collection<DexProgramClass> findSynthesizedFrom(Builder<?> builder, DexType holder) {
+ for (DexProgramClass synthesizedClass : builder.getSynthesizedClasses()) {
+ if (holder == synthesizedClass.getType()) {
+ return synthesizedClass.getSynthesizedFrom();
+ }
+ }
+ return null;
+ }
+
+ public void synthesizeUtilityClass(Builder<?> builder, InternalOptions options) {
+ if (holders.isEmpty()) {
+ return;
+ }
+ Set<DexProgramClass> referencingClasses = Sets.newConcurrentHashSet();
+ for (DexType holder : holders) {
+ DexClass definitionFor = converter.appInfo.definitionFor(holder);
+ if (definitionFor == null) {
+ Collection<DexProgramClass> synthesizedFrom = findSynthesizedFrom(builder, holder);
+ assert synthesizedFrom != null;
+ referencingClasses.addAll(synthesizedFrom);
+ } else {
+ referencingClasses.add(definitionFor.asProgramClass());
+ }
+ }
+ MethodAccessFlags flags = MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_STATIC | Constants.ACC_SYNTHETIC, false);
+ ClassAccessFlags classAccessFlags =
+ ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
+
+ for (MethodGenerator generator : methodGenerators.values()) {
+ DexMethod method = generator.generateMethod(factory);
+ TemplateMethodCode code = generator.generateTemplateMethod(options, method);
+ DexEncodedMethod dexEncodedMethod= new DexEncodedMethod(method,
+ flags, DexAnnotationSet.empty(), ParameterAnnotationsList.empty(), code);
+ DexProgramClass utilityClass =
+ new DexProgramClass(
+ method.holder,
+ null,
+ new SynthesizedOrigin("java8 methods utility class", getClass()),
+ classAccessFlags,
+ factory.objectType,
+ DexTypeList.empty(),
+ null,
+ null,
+ Collections.emptyList(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ new DexEncodedMethod[]{dexEncodedMethod},
+ DexEncodedMethod.EMPTY_ARRAY,
+ factory.getSkipNameValidationForTesting(),
+ referencingClasses);
+ code.setUpContext(utilityClass);
+ boolean addToMainDexList = referencingClasses.stream()
+ .anyMatch(clazz -> converter.appInfo.isInMainDexList(clazz.type));
+ converter.optimizeSynthesizedClass(utilityClass);
+ builder.addSynthesizedClass(utilityClass, addToMainDexList);
+ }
+ }
+
+ private MethodGenerator getMethodGeneratorOrNull(IRConverter converter, DexMethod method) {
+ DexMethod original = converter.graphLense().getOriginalMethodSignature(method);
+ assert original != null;
+ return rewritableMethods.getGenerator(
+ original.holder.descriptor, original.name, original.proto);
+ }
+
+
+ private static final class IntegerMethods extends TemplateMethodCode {
+ IntegerMethods(InternalOptions options, DexMethod method, String methodName) {
+ super(options, method, methodName, method.proto.toDescriptorString());
+ }
+
+ public static IntegerMethods hashCodeCode(InternalOptions options, DexMethod method) {
+ return new IntegerMethods(options, method, "hashCodeImpl");
+ }
+
+ public static IntegerMethods maxCode(InternalOptions options, DexMethod method) {
+ return new IntegerMethods(options, method, "maxImpl");
+ }
+
+ public static IntegerMethods minCode(InternalOptions options, DexMethod method) {
+ return new IntegerMethods(options, method, "minImpl");
+ }
+
+ public static IntegerMethods sumCode(InternalOptions options, DexMethod method) {
+ return new IntegerMethods(options, method, "sumImpl");
+ }
+
+ public static int hashCodeImpl(int i) {
+ return Integer.valueOf(i).hashCode();
+ }
+
+ public static int maxImpl(int a, int b) {
+ return java.lang.Math.max(a, b);
+ }
+
+ public static int minImpl(int a, int b) {
+ return java.lang.Math.min(a, b);
+ }
+
+ public static int sumImpl(int a, int b) {
+ return a + b;
+ }
+ }
+
+ private static final class DoubleMethods extends TemplateMethodCode {
+ DoubleMethods(InternalOptions options, DexMethod method, String methodName) {
+ super(options, method, methodName, method.proto.toDescriptorString());
+ }
+
+ public static DoubleMethods hashCodeCode(InternalOptions options, DexMethod method) {
+ return new DoubleMethods(options, method, "hashCodeImpl");
+ }
+
+ public static DoubleMethods maxCode(InternalOptions options, DexMethod method) {
+ return new DoubleMethods(options, method, "maxImpl");
+ }
+
+ public static DoubleMethods minCode(InternalOptions options, DexMethod method) {
+ return new DoubleMethods(options, method, "minImpl");
+ }
+
+ public static DoubleMethods sumCode(InternalOptions options, DexMethod method) {
+ return new DoubleMethods(options, method, "sumImpl");
+ }
+
+ public static DoubleMethods isFiniteCode(InternalOptions options, DexMethod method) {
+ return new DoubleMethods(options, method, "isFiniteImpl");
+ }
+
+ public static int hashCodeImpl(double d) {
+ return Double.valueOf(d).hashCode();
+ }
+
+ public static double maxImpl(double a, double b) {
+ return java.lang.Math.max(a, b);
+ }
+
+ public static double minImpl(double a, double b) {
+ return java.lang.Math.min(a, b);
+ }
+
+ public static double sumImpl(double a, double b) {
+ return a + b;
+ }
+
+ public static boolean isFiniteImpl(double d) {
+ Double boxed = Double.valueOf(d);
+ return !boxed.isInfinite() && !boxed.isNaN();
+ }
+ }
+
+ private static final class FloatMethods extends TemplateMethodCode {
+ FloatMethods(InternalOptions options, DexMethod method, String methodName) {
+ super(options, method, methodName, method.proto.toDescriptorString());
+ }
+
+ public static FloatMethods hashCodeCode(InternalOptions options, DexMethod method) {
+ return new FloatMethods(options, method, "hashCodeImpl");
+ }
+
+ public static FloatMethods maxCode(InternalOptions options, DexMethod method) {
+ return new FloatMethods(options, method, "maxImpl");
+ }
+
+ public static FloatMethods minCode(InternalOptions options, DexMethod method) {
+ return new FloatMethods(options, method, "minImpl");
+ }
+
+ public static FloatMethods sumCode(InternalOptions options, DexMethod method) {
+ return new FloatMethods(options, method, "sumImpl");
+ }
+
+ public static FloatMethods isFiniteCode(InternalOptions options, DexMethod method) {
+ return new FloatMethods(options, method, "isFiniteImpl");
+ }
+
+ public static int hashCodeImpl(float d) {
+ return Float.valueOf(d).hashCode();
+ }
+
+ public static float maxImpl(float a, float b) {
+ return java.lang.Math.max(a, b);
+ }
+
+ public static float minImpl(float a, float b) {
+ return java.lang.Math.min(a, b);
+ }
+
+ public static float sumImpl(float a, float b) {
+ return a + b;
+ }
+
+ public static boolean isFiniteImpl(float d) {
+ Float boxed = Float.valueOf(d);
+ return !boxed.isInfinite() && !boxed.isNaN();
+ }
+ }
+
+ private static final class BooleanMethods extends TemplateMethodCode {
+ BooleanMethods(InternalOptions options, DexMethod method, String methodName) {
+ super(options, method, methodName, method.proto.toDescriptorString());
+ }
+
+ public static BooleanMethods hashCodeCode(InternalOptions options, DexMethod method) {
+ return new BooleanMethods(options, method, "hashCodeImpl");
+ }
+
+ public static BooleanMethods logicalAndCode(InternalOptions options, DexMethod method) {
+ return new BooleanMethods(options, method, "logicalAndImpl");
+ }
+
+ public static BooleanMethods logicalOrCode(InternalOptions options, DexMethod method) {
+ return new BooleanMethods(options, method, "logicalOrImpl");
+ }
+
+ public static BooleanMethods logicalXorCode(InternalOptions options, DexMethod method) {
+ return new BooleanMethods(options, method, "logicalXorImpl");
+ }
+
+ public static int hashCodeImpl(boolean b) {
+ return Boolean.valueOf(b).hashCode();
+ }
+
+ public static boolean logicalAndImpl(boolean a, boolean b) {
+ return a && b;
+ }
+
+ public static boolean logicalOrImpl(boolean a, boolean b) {
+ return a || b;
+ }
+
+ public static boolean logicalXorImpl(boolean a, boolean b) {
+ return a ^ b;
+ }
+ }
+
+ public static final class RewritableMethods {
+ // Map class, method, proto to a generator for creating the code and method.
+ private final Map<DexString, Map<DexString, Map<DexProto, MethodGenerator>>> rewritable;
+
+
+ public RewritableMethods(DexItemFactory factory) {
+ rewritable = new HashMap<>();
+ // Integer
+ DexString clazz = factory.boxedIntDescriptor;
+
+ // int Integer.hashCode(int i)
+ DexString method = factory.createString("hashCode");
+ DexProto proto = factory.createProto(factory.intType, factory.intType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(IntegerMethods::hashCodeCode, clazz, method, proto));
+
+ // int Integer.max(int a, int b)
+ method = factory.createString("max");
+ proto = factory.createProto(factory.intType, factory.intType, factory.intType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(IntegerMethods::maxCode, clazz, method, proto));
+
+ // int Integer.min(int a, int b)
+ method = factory.createString("min");
+ proto = factory.createProto(factory.intType, factory.intType, factory.intType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(IntegerMethods::minCode, clazz, method, proto));
+
+ // int Integer.sum(int a, int b)
+ method = factory.createString("sum");
+ proto = factory.createProto(factory.intType, factory.intType, factory.intType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(IntegerMethods::sumCode, clazz, method, proto));
+
+ // Double
+ clazz = factory.boxedDoubleDescriptor;
+
+ // int Double.hashCode(double d)
+ method = factory.createString("hashCode");
+ proto = factory.createProto(factory.intType, factory.doubleType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(DoubleMethods::hashCodeCode, clazz, method, proto));
+
+ // double Double.max(double a, double b)
+ method = factory.createString("max");
+ proto = factory.createProto(factory.doubleType, factory.doubleType, factory.doubleType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(DoubleMethods::maxCode, clazz, method, proto));
+
+ // double Double.min(double a, double b)
+ method = factory.createString("min");
+ proto = factory.createProto(factory.doubleType, factory.doubleType, factory.doubleType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(DoubleMethods::minCode, clazz, method, proto));
+
+ // double Double.sum(double a, double b)
+ method = factory.createString("sum");
+ proto = factory.createProto(factory.doubleType, factory.doubleType, factory.doubleType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(DoubleMethods::sumCode, clazz, method, proto));
+
+ // boolean Double.isFinite(double a)
+ method = factory.createString("isFinite");
+ proto = factory.createProto(factory.booleanType, factory.doubleType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(DoubleMethods::isFiniteCode, clazz, method, proto));
+
+ // Float
+ clazz = factory.boxedFloatDescriptor;
+
+ // int Float.hashCode(float d)
+ method = factory.createString("hashCode");
+ proto = factory.createProto(factory.intType, factory.floatType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(FloatMethods::hashCodeCode, clazz, method, proto));
+
+ // float Float.max(float a, float b)
+ method = factory.createString("max");
+ proto = factory.createProto(factory.floatType, factory.floatType, factory.floatType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(FloatMethods::maxCode, clazz, method, proto));
+
+ // float Float.min(float a, float b)
+ method = factory.createString("min");
+ proto = factory.createProto(factory.floatType, factory.floatType, factory.floatType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(FloatMethods::minCode, clazz, method, proto));
+
+ // float Float.sum(float a, float b)
+ method = factory.createString("sum");
+ proto = factory.createProto(factory.floatType, factory.floatType, factory.floatType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(FloatMethods::sumCode, clazz, method, proto));
+
+ // boolean Float.isFinite(float a)
+ method = factory.createString("isFinite");
+ proto = factory.createProto(factory.booleanType, factory.floatType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(FloatMethods::isFiniteCode, clazz, method, proto));
+
+ // Boolean
+ clazz = factory.boxedBooleanDescriptor;
+
+ // int Boolean.hashCode(boolean b)
+ method = factory.createString("hashCode");
+ proto = factory.createProto(factory.intType, factory.booleanType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(BooleanMethods::hashCodeCode, clazz, method, proto));
+
+ // boolean Boolean.logicalAnd(boolean a, boolean b)
+ method = factory.createString("logicalAnd");
+ proto = factory.createProto(factory.booleanType, factory.booleanType, factory.booleanType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(BooleanMethods::logicalAndCode, clazz, method, proto));
+
+ // boolean Boolean.logicalOr(boolean a, boolean b)
+ method = factory.createString("logicalOr");
+ proto = factory.createProto(factory.booleanType, factory.booleanType, factory.booleanType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(BooleanMethods::logicalOrCode, clazz, method, proto));
+
+ // boolean Boolean.logicalXor(boolean a, boolean b)
+ method = factory.createString("logicalXor");
+ proto = factory.createProto(factory.booleanType, factory.booleanType, factory.booleanType);
+ addOrGetMethod(clazz, method)
+ .put(proto, new MethodGenerator(BooleanMethods::logicalXorCode, clazz, method, proto));
+ }
+
+ private Map<DexString, Map<DexProto, MethodGenerator>> addOrGetClass(DexString clazz) {
+ return rewritable.computeIfAbsent(clazz, k -> new HashMap<>());
+ }
+
+ private Map<DexProto, MethodGenerator> addOrGetMethod(
+ DexString clazz, DexString method) {
+ return addOrGetClass(clazz).computeIfAbsent(method, k -> new HashMap<>());
+ }
+
+ public MethodGenerator getGenerator(DexString clazz, DexString method, DexProto proto) {
+ Map<DexString, Map<DexProto, MethodGenerator>> classMap = rewritable.get(clazz);
+ if (classMap != null) {
+ Map<DexProto, MethodGenerator> methodMap = classMap.get(method);
+ if (methodMap != null) {
+ return methodMap.get(proto);
+ }
+ }
+ return null;
+ }
+
+ public static class MethodGenerator {
+ private final BiFunction<InternalOptions, DexMethod, TemplateMethodCode> generator;
+ private final DexString clazz;
+ private final DexString method;
+ private final DexProto proto;
+ private DexMethod dexMethod;
+
+ public MethodGenerator(
+ BiFunction<InternalOptions, DexMethod, TemplateMethodCode> generator,
+ DexString clazz, DexString method, DexProto proto) {
+ this.generator = generator;
+ this.clazz = clazz;
+ this.method = method;
+ this.proto = proto;
+ }
+
+ public DexMethod generateMethod(DexItemFactory factory) {
+ if (dexMethod != null) {
+ return dexMethod;
+ }
+ String clazzDescriptor = DescriptorUtils.getSimpleClassNameFromDescriptor(clazz.toString());
+ String postFix = "$" + clazzDescriptor + "$" + method + "$" + proto.shorty.toString();
+ DexType clazz = factory.createType(UTILITY_CLASS_DESCRIPTOR_PREFIX + postFix + ";");
+ dexMethod = factory.createMethod(clazz, proto, method);
+ return dexMethod;
+ }
+
+ public TemplateMethodCode generateTemplateMethod(InternalOptions options, DexMethod method) {
+ return generator.apply(options, method);
+ }
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/TemplateMethodCode.java b/src/main/java/com/android/tools/r8/ir/synthetic/TemplateMethodCode.java
index fdca28c..5162b6f 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/TemplateMethodCode.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/TemplateMethodCode.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.synthetic;
+import com.android.tools.r8.KeepSubclassesForCodeGeneration;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
@@ -17,6 +18,7 @@
import java.util.function.BiFunction;
// Source code representing code of a method generated based on a template.
+@KeepSubclassesForCodeGeneration
public abstract class TemplateMethodCode extends JarCode {
private final String templateMethodName;
private final String templateMethodDesc;
diff --git a/src/main/java/com/android/tools/r8/shaking/CollectingGraphConsumer.java b/src/main/java/com/android/tools/r8/shaking/CollectingGraphConsumer.java
index 774a93a..27bdd95 100644
--- a/src/main/java/com/android/tools/r8/shaking/CollectingGraphConsumer.java
+++ b/src/main/java/com/android/tools/r8/shaking/CollectingGraphConsumer.java
@@ -3,9 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import com.android.tools.r8.graphinfo.GraphConsumer;
-import com.android.tools.r8.graphinfo.GraphEdgeInfo;
-import com.android.tools.r8.graphinfo.GraphNode;
+import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
+import com.android.tools.r8.experimental.graphinfo.GraphEdgeInfo;
+import com.android.tools.r8.experimental.graphinfo.GraphNode;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.Map;
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index 6a90323..95f077d 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -11,6 +11,15 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.experimental.graphinfo.AnnotationGraphNode;
+import com.android.tools.r8.experimental.graphinfo.ClassGraphNode;
+import com.android.tools.r8.experimental.graphinfo.FieldGraphNode;
+import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
+import com.android.tools.r8.experimental.graphinfo.GraphEdgeInfo;
+import com.android.tools.r8.experimental.graphinfo.GraphEdgeInfo.EdgeKind;
+import com.android.tools.r8.experimental.graphinfo.GraphNode;
+import com.android.tools.r8.experimental.graphinfo.KeepRuleGraphNode;
+import com.android.tools.r8.experimental.graphinfo.MethodGraphNode;
import com.android.tools.r8.graph.AppInfo.ResolutionResult;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.AppView;
@@ -37,15 +46,6 @@
import com.android.tools.r8.graph.GraphLense;
import com.android.tools.r8.graph.KeyedDexItem;
import com.android.tools.r8.graph.PresortedComparable;
-import com.android.tools.r8.graphinfo.AnnotationGraphNode;
-import com.android.tools.r8.graphinfo.ClassGraphNode;
-import com.android.tools.r8.graphinfo.FieldGraphNode;
-import com.android.tools.r8.graphinfo.GraphConsumer;
-import com.android.tools.r8.graphinfo.GraphEdgeInfo;
-import com.android.tools.r8.graphinfo.GraphEdgeInfo.EdgeKind;
-import com.android.tools.r8.graphinfo.GraphNode;
-import com.android.tools.r8.graphinfo.KeepRuleGraphNode;
-import com.android.tools.r8.graphinfo.MethodGraphNode;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
import com.android.tools.r8.ir.code.Invoke.Type;
diff --git a/src/main/java/com/android/tools/r8/shaking/KeepReason.java b/src/main/java/com/android/tools/r8/shaking/KeepReason.java
index 82737a6..16d78a7 100644
--- a/src/main/java/com/android/tools/r8/shaking/KeepReason.java
+++ b/src/main/java/com/android/tools/r8/shaking/KeepReason.java
@@ -3,12 +3,12 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
+import com.android.tools.r8.experimental.graphinfo.GraphEdgeInfo;
+import com.android.tools.r8.experimental.graphinfo.GraphEdgeInfo.EdgeKind;
+import com.android.tools.r8.experimental.graphinfo.GraphNode;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graphinfo.GraphEdgeInfo;
-import com.android.tools.r8.graphinfo.GraphEdgeInfo.EdgeKind;
-import com.android.tools.r8.graphinfo.GraphNode;
// TODO(herhut): Canonicalize reason objects.
public abstract class KeepReason {
@@ -50,7 +50,7 @@
}
public static KeepReason fieldReferencedIn(DexEncodedMethod method) {
- return new ReferenedFrom(method);
+ return new ReferencedFrom(method);
}
public static KeepReason referencedInAnnotation(DexItem holder) {
@@ -219,9 +219,9 @@
}
}
- private static class ReferenedFrom extends BasedOnOtherMethod {
+ private static class ReferencedFrom extends BasedOnOtherMethod {
- private ReferenedFrom(DexEncodedMethod method) {
+ private ReferencedFrom(DexEncodedMethod method) {
super(method);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index c012898..6cf0da0 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -8,8 +8,10 @@
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.EnclosingMethodAttribute;
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.KeyedDexItem;
import com.android.tools.r8.graph.PresortedComparable;
@@ -102,15 +104,44 @@
clazz.setInstanceFields(reachableFields(clazz.instanceFields()));
clazz.setStaticFields(reachableFields(clazz.staticFields()));
clazz.removeInnerClasses(this::isAttributeReferencingPrunedType);
+ clazz.removeEnclosingMethod(this::isAttributeReferencingPrunedItem);
usagePrinter.visited();
}
}
return newClasses;
}
+ private boolean isAttributeReferencingPrunedItem(EnclosingMethodAttribute attr) {
+ return
+ (attr.getEnclosingClass() != null
+ && !appInfo.liveTypes.contains(attr.getEnclosingClass()))
+ || (attr.getEnclosingMethod() != null
+ && !appInfo.liveMethods.contains(attr.getEnclosingMethod()));
+ }
+
private boolean isAttributeReferencingPrunedType(InnerClassAttribute attr) {
- return (attr.getInner() != null && !appInfo.liveTypes.contains(attr.getInner()))
- || (attr.getOuter() != null && !appInfo.liveTypes.contains(attr.getOuter()));
+ if (!appInfo.liveTypes.contains(attr.getInner())) {
+ return true;
+ }
+ DexType context = attr.getOuter();
+ if (context == null) {
+ DexClass inner = appInfo.definitionFor(attr.getInner());
+ if (inner != null && inner.getEnclosingMethod() != null) {
+ EnclosingMethodAttribute enclosingMethodAttribute = inner.getEnclosingMethod();
+ if (enclosingMethodAttribute.getEnclosingClass() != null) {
+ context = enclosingMethodAttribute.getEnclosingClass();
+ } else {
+ DexMethod enclosingMethod = enclosingMethodAttribute.getEnclosingMethod();
+ if (!appInfo.liveMethods.contains(enclosingMethod)) {
+ // EnclosingMethodAttribute will be pruned as it references the pruned method.
+ // Hence, removal of the current InnerClassAttribute too.
+ return true;
+ }
+ context = enclosingMethod.getHolder();
+ }
+ }
+ }
+ return context == null || !appInfo.liveTypes.contains(context);
}
private <S extends PresortedComparable<S>, T extends KeyedDexItem<S>> int firstUnreachableIndex(
diff --git a/src/main/java/com/android/tools/r8/shaking/WhyAreYouKeepingConsumer.java b/src/main/java/com/android/tools/r8/shaking/WhyAreYouKeepingConsumer.java
index 11f2131..0572e88 100644
--- a/src/main/java/com/android/tools/r8/shaking/WhyAreYouKeepingConsumer.java
+++ b/src/main/java/com/android/tools/r8/shaking/WhyAreYouKeepingConsumer.java
@@ -4,14 +4,14 @@
package com.android.tools.r8.shaking;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graphinfo.ClassGraphNode;
-import com.android.tools.r8.graphinfo.FieldGraphNode;
-import com.android.tools.r8.graphinfo.GraphConsumer;
-import com.android.tools.r8.graphinfo.GraphEdgeInfo;
-import com.android.tools.r8.graphinfo.GraphEdgeInfo.EdgeKind;
-import com.android.tools.r8.graphinfo.GraphNode;
-import com.android.tools.r8.graphinfo.KeepRuleGraphNode;
-import com.android.tools.r8.graphinfo.MethodGraphNode;
+import com.android.tools.r8.experimental.graphinfo.ClassGraphNode;
+import com.android.tools.r8.experimental.graphinfo.FieldGraphNode;
+import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
+import com.android.tools.r8.experimental.graphinfo.GraphEdgeInfo;
+import com.android.tools.r8.experimental.graphinfo.GraphEdgeInfo.EdgeKind;
+import com.android.tools.r8.experimental.graphinfo.GraphNode;
+import com.android.tools.r8.experimental.graphinfo.KeepRuleGraphNode;
+import com.android.tools.r8.experimental.graphinfo.MethodGraphNode;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
import com.android.tools.r8.position.TextPosition;
diff --git a/src/main/java/com/android/tools/r8/utils/ClassMap.java b/src/main/java/com/android/tools/r8/utils/ClassMap.java
index 0ebfb9d..33c1bf3 100644
--- a/src/main/java/com/android/tools/r8/utils/ClassMap.java
+++ b/src/main/java/com/android/tools/r8/utils/ClassMap.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.graph.ClassKind;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexType;
+import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Iterator;
@@ -134,6 +135,18 @@
return loadedClasses;
}
+ public Map<DexType, DexClass> getAllClassesInMap() {
+ if (classProvider.get() != null) {
+ throw new Unreachable("Getting all classes from not fully loaded collection.");
+ }
+ ImmutableMap.Builder<DexType, DexClass> builder = ImmutableMap.builder();
+ // This is fully loaded, so the class map will no longer change.
+ for (Map.Entry<DexType, Supplier<T>> entry : classes.entrySet()) {
+ builder.put(entry.getKey(), entry.getValue().get());
+ }
+ return builder.build();
+ }
+
public Iterable<DexType> getAllTypes() {
return classes.keySet();
}
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 388cac3..90b9e18 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -14,11 +14,11 @@
import com.android.tools.r8.dex.Marker;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.InvalidDebugInfoException;
+import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graphinfo.GraphConsumer;
import com.android.tools.r8.ir.optimize.Inliner;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.ProguardConfiguration;
diff --git a/src/main/keep.txt b/src/main/keep.txt
index 4b987e8..61b2b14 100644
--- a/src/main/keep.txt
+++ b/src/main/keep.txt
@@ -4,6 +4,8 @@
-keep @com.android.tools.r8.Keep class * { public *; }
-keep @com.android.tools.r8.KeepForSubclassing class * { public *; protected *; }
+-keep class * extends @com.android.tools.r8.KeepSubclassesForCodeGeneration * { public *; }
+
-keep public class com.android.tools.r8.D8 { public static void main(java.lang.String[]); }
-keep public class com.android.tools.r8.R8 { public static void main(java.lang.String[]); }
diff --git a/src/test/java/com/android/tools/r8/D8ApiBinaryCompatibilityTests.java b/src/test/java/com/android/tools/r8/D8ApiBinaryCompatibilityTests.java
index 6d0ef5a..c5e44a3 100644
--- a/src/test/java/com/android/tools/r8/D8ApiBinaryCompatibilityTests.java
+++ b/src/test/java/com/android/tools/r8/D8ApiBinaryCompatibilityTests.java
@@ -49,13 +49,16 @@
Path mainDexList = temp.getRoot().toPath().resolve("maindexlist.txt");
FileUtils.writeTextFile(mainDexList, "desugaringwithmissingclasstest1/Main.class");
+ // It is important to place the api usage sample jar after the current classpath because we want
+ // to find D8/R8 classes before the ones in the jar, otherwise renamed classes and fields cannot
+ // be found.
+ String classPath = System.getProperty("java.class.path") + File.pathSeparator + jar.toString();
List<String> command =
ImmutableList.<String>builder()
.addAll(
ImmutableList.of(
ToolHelper.getJavaExecutable(),
- "-cp",
- jar.toString() + File.pathSeparator + System.getProperty("java.class.path"),
+ "-cp", classPath,
main,
// Compiler arguments.
"--output",
diff --git a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
index c8d6bd9..19e54bb 100644
--- a/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
+++ b/src/test/java/com/android/tools/r8/ProguardTestBuilder.java
@@ -209,6 +209,18 @@
}
@Override
+ public ProguardTestBuilder addKeepRuleFiles(List<Path> files) {
+ try {
+ for (Path file : files) {
+ config.addAll(FileUtils.readAllLines(file));
+ }
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ return self();
+ }
+
+ @Override
public ProguardTestBuilder addKeepRules(Collection<String> rules) {
config.addAll(rules);
return self();
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 8c4f682..2c72ec7 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -6,10 +6,11 @@
import com.android.tools.r8.R8Command.Builder;
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.TestBase.R8Mode;
-import com.android.tools.r8.graphinfo.GraphConsumer;
+import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
+import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
@@ -74,6 +75,12 @@
}
@Override
+ public R8TestBuilder addKeepRuleFiles(List<Path> files) {
+ builder.addProguardConfigurationFiles(files);
+ return self();
+ }
+
+ @Override
public R8TestBuilder addKeepRules(Collection<String> rules) {
builder.addProguardConfiguration(new ArrayList<>(rules), Origin.unknown());
return self();
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index e7e91e0..42b56ca 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -7,12 +7,12 @@
import com.android.tools.r8.TestBase.Backend;
import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.TypeReference;
-import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.StringUtils;
import java.io.IOException;
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
+import java.util.List;
public abstract class TestShrinkerBuilder<
C extends BaseCompilerCommand,
@@ -30,8 +30,10 @@
public abstract T noMinification();
- public T addKeepRules(Path path) throws IOException {
- return addKeepRules(FileUtils.readAllLines(path));
+ public abstract T addKeepRuleFiles(List<Path> files);
+
+ public T addKeepRuleFiles(Path... files) throws IOException {
+ return addKeepRuleFiles(Arrays.asList(files));
}
public abstract T addKeepRules(Collection<String> rules);
diff --git a/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java b/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
new file mode 100644
index 0000000..8139694
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
@@ -0,0 +1,84 @@
+// 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.desugar;
+
+import com.android.tools.r8.TestBase;
+import org.junit.Before;
+import org.junit.Test;
+
+public class Java8MethodsTest extends TestBase {
+ static String expectedOutput = "";
+
+ @Before
+ public void testJvm() throws Exception {
+ expectedOutput = testForJvm()
+ .addTestClasspath()
+ .run(Java8Methods.class).getStdOut();
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ testForD8()
+ .addProgramClasses(Java8Methods.class)
+ .run(Java8Methods.class)
+ .assertSuccessWithOutput(expectedOutput);
+ }
+
+ static class Java8Methods {
+ public static void main(String[] args) {
+ int[] aInts = new int[]{42, 1, -1, Integer.MAX_VALUE, Integer.MIN_VALUE};
+ int[] bInts = new int[]{43, 1, -1, Integer.MAX_VALUE, Integer.MIN_VALUE};
+ for (int aInt : aInts) {
+ System.out.println(Integer.hashCode(aInt));
+ for (int bInt : bInts) {
+ System.out.println(Integer.max(aInt, bInt));
+ System.out.println(Integer.min(aInt, bInt));
+ System.out.println(Integer.sum(aInt, bInt));
+ }
+ }
+
+ double[] aDoubles = new double[]{42.0, 1.1, -1.1, Double.MAX_VALUE, Double.MIN_NORMAL,
+ Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY};
+ double[] bDoubles = new double[]{43, 1.2, -1.3, Double.MAX_VALUE, Double.MIN_NORMAL,
+ Double.NaN, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY};
+ for (double aDouble : aDoubles) {
+ System.out.println(Double.hashCode(aDouble));
+ System.out.println(Double.isFinite(aDouble));
+ for (double bDouble : bDoubles) {
+ System.out.println(Double.max(aDouble, bDouble));
+ System.out.println(Double.min(aDouble, bDouble));
+ System.out.println(Double.sum(aDouble, bDouble));
+ }
+ }
+
+ // Float.MAX_VALUE/MIN_VALUE printed values differs between jvm and art on some versions,
+ // e.g., 1.17549435E-38 on jvm, 1.1754944E-38 on art
+ float[] aFloats = new float[]{42.0f, 1.1f, -1.1f, Float.MAX_VALUE, Float.MIN_NORMAL,
+ Float.NaN, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY};
+ float[] bFloats = new float[]{43, 1.2f, -1.3f, Float.MAX_VALUE, Float.MIN_NORMAL,
+ Float.NaN, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY};
+ for (float aFloat : aFloats) {
+ System.out.println(Float.hashCode(aFloat));
+ System.out.println(Float.isFinite(aFloat));
+ for (float bFloat : bFloats) {
+ // Print comparison, since Max/Min printed values differs between jvm and art
+ System.out.println(Float.max(aFloat, bFloat) == aFloat);
+ System.out.println(Float.min(aFloat, bFloat) == aFloat);
+ // Compare to the calculated sum, again, Max/Min values may differ
+ System.out.println(Float.sum(aFloat, bFloat) == (aFloat + bFloat));
+ }
+ }
+
+ for (boolean aBoolean : new boolean[]{true, false}) {
+ System.out.println(aBoolean);
+ for (boolean bBoolean : new boolean[]{true, false}) {
+ System.out.println(Boolean.logicalAnd(aBoolean, bBoolean));
+ System.out.println(Boolean.logicalOr(aBoolean, bBoolean));
+ System.out.println(Boolean.logicalXor(aBoolean, bBoolean));
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java
index 9cc69fa..54f9df3 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTest.java
@@ -263,7 +263,7 @@
.addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
.addKeepRules("-printmapping " + createNewMappingPath().toAbsolutePath().toString());
if (!enableMinification) {
- builder.addKeepRules("-dontobfuscate");
+ builder.noMinification();
}
TestRunResult result =
builder
@@ -284,7 +284,7 @@
.addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
.addKeepRules("-printmapping " + createNewMappingPath().toAbsolutePath().toString());
if (!enableMinification) {
- builder.addKeepRules("-dontobfuscate");
+ builder.noMinification();
}
TestRunResult result =
builder
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
index b75e4ee..5a9ca75 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetSimpleNameTest.java
@@ -124,7 +124,7 @@
"Inner",
"Inner"
);
- private static final String OUTPUT_WITH_SHRUNK_ATTRIBUTE = StringUtils.lines(
+ private static final String OUTPUT_WITH_SHRUNK_ATTRIBUTES = StringUtils.lines(
"Local_t03",
"InnerLocal",
"$",
@@ -211,7 +211,7 @@
.addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
.addKeepRules("-printmapping " + createNewMappingPath().toAbsolutePath().toString());
if (!enableMinification) {
- builder.addKeepRules("-dontobfuscate");
+ builder.noMinification();
}
TestRunResult result =
builder
@@ -231,12 +231,12 @@
.addKeepRules("-keep,allowobfuscation class **.ClassGetSimpleName*")
// See b/119471127: some old VMs are not resilient to broken attributes.
// Comment out the following line to reproduce b/120130435
- // then use OUTPUT_WITH_SHRUNK_ATTRIBUTE
+ // then use OUTPUT_WITH_SHRUNK_ATTRIBUTES
.addKeepRules("-keep,allowobfuscation class **.Outer*")
.addKeepRules("-keepattributes InnerClasses,EnclosingMethod")
.addKeepRules("-printmapping " + createNewMappingPath().toAbsolutePath().toString());
if (!enableMinification) {
- builder.addKeepRules("-dontobfuscate");
+ builder.noMinification();
}
R8TestRunResult result =
builder
diff --git a/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java b/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
index 3eed543..0acd733 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/whyareyoukeeping/MainDexListWhyAreYouKeeping.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.graphinfo.GraphConsumer;
+import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer;
diff --git a/src/test/java/com/android/tools/r8/shaking/EnclosingMethodTest.java b/src/test/java/com/android/tools/r8/shaking/EnclosingMethodTest.java
index c14cef5..4e121a8 100644
--- a/src/test/java/com/android/tools/r8/shaking/EnclosingMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/EnclosingMethodTest.java
@@ -49,6 +49,8 @@
private final boolean enableMinification;
private Collection<Path> classPaths;
private static final String JAVA_OUTPUT = "-Returned-null-" + System.lineSeparator();
+ private static final String OUTPUT_WITH_SHRUNK_ATTRIBUTES =
+ "com.android.tools.r8.shaking.GetNameClass$1" + System.lineSeparator();
private static final Class<?> MAIN = GetNameMain.class;
@Parameterized.Parameters(name = "Backend: {0} minification: {1}")
@@ -88,18 +90,10 @@
.addKeepRules("-keep class **.GetName*")
.addKeepRules("-keepattributes InnerClasses,EnclosingMethod");
if (!enableMinification) {
- builder.addKeepRules("-dontobfuscate");
+ builder.noMinification();
}
R8TestRunResult result = builder.run(MAIN);
- if (backend == Backend.DEX) {
- if (ToolHelper.getDexVm().getVersion().isNewerThan(Version.V4_4_4)
- && ToolHelper.getDexVm().getVersion().isOlderThanOrEqual(Version.V6_0_1)) {
- result.assertFailureWithErrorThatMatches(containsString("IncompatibleClassChangeError"));
- return;
- }
- }
-
- result.assertSuccessWithOutput(JAVA_OUTPUT);
+ result.assertSuccessWithOutput(OUTPUT_WITH_SHRUNK_ATTRIBUTES);
}
}
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptMethodTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptMethodTest.java
index 689d3b6..35083c7 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptMethodTest.java
@@ -19,6 +19,9 @@
import java.io.IOException;
import java.util.concurrent.ExecutionException;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
class Main {
@@ -37,9 +40,19 @@
}
}
+@RunWith(Parameterized.class)
public class KeptMethodTest extends TestBase {
- final Backend backend = Backend.DEX;
+ private final Backend backend;
+
+ @Parameters(name = "{0}")
+ public static Backend[] data() {
+ return Backend.values();
+ }
+
+ public KeptMethodTest(Backend backend) {
+ this.backend = backend;
+ }
@Test
public void testKeptMethod()
diff --git a/src/test/java/com/android/tools/r8/shaking/proxy/MockitoTest.java b/src/test/java/com/android/tools/r8/shaking/proxy/MockitoTest.java
index 48cdb05..95963a0 100644
--- a/src/test/java/com/android/tools/r8/shaking/proxy/MockitoTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/proxy/MockitoTest.java
@@ -48,7 +48,7 @@
Path flagToKeepTestRunner = Paths.get(ToolHelper.EXAMPLES_DIR, M_I_PKG, "keep-rules.txt");
R8TestBuilder builder = testForR8(backend)
.addProgramFiles(MOCKITO_INTERFACE_JAR)
- .addKeepRules(flagToKeepTestRunner);
+ .addKeepRuleFiles(flagToKeepTestRunner);
if (!minify) {
builder.noMinification();
}
@@ -65,7 +65,7 @@
Paths.get(ToolHelper.EXAMPLES_DIR, M_I_PKG, "keep-rules-conditional-on-mock.txt");
R8TestBuilder builder = testForR8(backend)
.addProgramFiles(MOCKITO_INTERFACE_JAR)
- .addKeepRules(flagToKeepInterfaceConditionally);
+ .addKeepRuleFiles(flagToKeepInterfaceConditionally);
if (!minify) {
builder.noMinification();
}
diff --git a/src/test/java/com/android/tools/r8/utils/graphinspector/GraphInspector.java b/src/test/java/com/android/tools/r8/utils/graphinspector/GraphInspector.java
index 454d1f5..b138e50 100644
--- a/src/test/java/com/android/tools/r8/utils/graphinspector/GraphInspector.java
+++ b/src/test/java/com/android/tools/r8/utils/graphinspector/GraphInspector.java
@@ -4,11 +4,11 @@
package com.android.tools.r8.utils.graphinspector;
import com.android.tools.r8.errors.Unimplemented;
-import com.android.tools.r8.graphinfo.ClassGraphNode;
-import com.android.tools.r8.graphinfo.FieldGraphNode;
-import com.android.tools.r8.graphinfo.GraphEdgeInfo;
-import com.android.tools.r8.graphinfo.GraphNode;
-import com.android.tools.r8.graphinfo.MethodGraphNode;
+import com.android.tools.r8.experimental.graphinfo.ClassGraphNode;
+import com.android.tools.r8.experimental.graphinfo.FieldGraphNode;
+import com.android.tools.r8.experimental.graphinfo.GraphEdgeInfo;
+import com.android.tools.r8.experimental.graphinfo.GraphNode;
+import com.android.tools.r8.experimental.graphinfo.MethodGraphNode;
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.references.FieldReference;
import com.android.tools.r8.references.MethodReference;