Merge "Temporary workaround for class merging issue with static interface invokes"
diff --git a/build.gradle b/build.gradle
index 5631d94..9e84b01 100644
--- a/build.gradle
+++ b/build.gradle
@@ -276,6 +276,8 @@
"android_jar/lib-v24",
"android_jar/lib-v25",
"android_jar/lib-v26",
+ "android_jar/lib-v27",
+ "android_jar/lib-v28",
"core-lambda-stubs",
"dart-sdk",
"ddmlib",
diff --git a/src/main/java/com/android/tools/r8/PrintUses.java b/src/main/java/com/android/tools/r8/PrintUses.java
index 42fed08..15f5662 100644
--- a/src/main/java/com/android/tools/r8/PrintUses.java
+++ b/src/main/java/com/android/tools/r8/PrintUses.java
@@ -22,7 +22,6 @@
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import java.io.IOException;
-import java.io.PrintStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
@@ -46,19 +45,20 @@
public class PrintUses {
private static final String USAGE =
- "Arguments: <rt.jar> <r8.jar> <sample.jar>\n"
+ "Arguments: [--keeprules] <rt.jar> <r8.jar> <sample.jar>\n"
+ "\n"
+ "PrintUses prints the classes, interfaces, methods and fields used by <sample.jar>,\n"
+ "restricted to classes and interfaces in <r8.jar> that are not in <sample.jar>.\n"
+ "<rt.jar> and <r8.jar> should point to libraries used by <sample.jar>.\n"
+ "\n"
+ "The output is in the same format as what is printed when specifying -printseeds in\n"
- + "a ProGuard configuration file. See also the "
+ + "a ProGuard configuration file. Use --keeprules for outputting proguard keep rules. "
+ + "See also the "
+ PrintSeeds.class.getSimpleName()
+ " program in R8.";
private final Set<String> descriptors;
- private final PrintStream out;
+ private final Printer printer;
private Set<DexType> types = Sets.newIdentityHashSet();
private Map<DexType, Set<DexMethod>> methods = Maps.newIdentityHashMap();
private Map<DexType, Set<DexField>> fields = Maps.newIdentityHashMap();
@@ -210,21 +210,28 @@
}
}
- public static void main(String[] args) throws Exception {
- if (args.length != 3) {
+ public static void main(String... args) throws Exception {
+ if (args.length != 3 && args.length != 4) {
System.out.println(USAGE.replace("\n", System.lineSeparator()));
return;
}
+ int argumentIndex = 0;
+ boolean printKeep = false;
+ if (args[0].equals("--keeprules")) {
+ printKeep = true;
+ argumentIndex++;
+ }
AndroidApp.Builder builder = AndroidApp.builder();
- Path rtJar = Paths.get(args[0]);
+ Path rtJar = Paths.get(args[argumentIndex++]);
builder.addLibraryFile(rtJar);
- Path r8Jar = Paths.get(args[1]);
+ Path r8Jar = Paths.get(args[argumentIndex++]);
builder.addLibraryFile(r8Jar);
- Path sampleJar = Paths.get(args[2]);
+ Path sampleJar = Paths.get(args[argumentIndex++]);
builder.addProgramFile(sampleJar);
Set<String> descriptors = new HashSet<>(getDescriptors(r8Jar));
descriptors.removeAll(getDescriptors(sampleJar));
- PrintUses printUses = new PrintUses(descriptors, builder.build(), System.out);
+ Printer printer = printKeep ? new KeepPrinter() : new DefaultPrinter();
+ PrintUses printUses = new PrintUses(descriptors, builder.build(), printer);
printUses.analyze();
printUses.print();
if (printUses.errors > 0) {
@@ -237,10 +244,10 @@
return new ArchiveClassFileProvider(path).getClassDescriptors();
}
- private PrintUses(Set<String> descriptors, AndroidApp inputApp, PrintStream out)
+ private PrintUses(Set<String> descriptors, AndroidApp inputApp, Printer printer)
throws Exception {
this.descriptors = descriptors;
- this.out = out;
+ this.printer = printer;
InternalOptions options = new InternalOptions();
application =
new ApplicationReader(inputApp, options, new Timing("PrintUses")).read().toDirect();
@@ -260,69 +267,178 @@
}
private void print() {
- List<DexType> types = new ArrayList<>(this.types);
- types.sort(Comparator.comparing(DexType::toSourceString));
- for (DexType type : types) {
- String typeName = type.toSourceString();
- DexClass dexClass = application.definitionFor(type);
- if (dexClass == null) {
- error("Could not find definition for type " + type.toSourceString());
- continue;
+ errors = printer.print(application, types, methods, fields);
+ }
+
+ private abstract static class Printer {
+
+ void append(String string) {
+ System.out.print(string);
+ }
+
+ void appendLine(String string) {
+ System.out.println(string);
+ }
+
+ void printArguments(DexMethod method) {
+ append("(");
+ for (int i = 0; i < method.getArity(); i++) {
+ if (i != 0) {
+ append(",");
+ }
+ append(method.proto.parameters.values[i].toSourceString());
}
- out.println(typeName);
- List<DexMethod> methods = new ArrayList<>(this.methods.get(type));
- List<String> methodDefinitions = new ArrayList<>(methods.size());
- for (DexMethod method : methods) {
- DexEncodedMethod encodedMethod = dexClass.lookupMethod(method);
- if (encodedMethod == null) {
- error("Could not find definition for method " + method.toSourceString());
+ append(")");
+ }
+
+ abstract void printConstructorName(DexEncodedMethod encodedMethod);
+
+ void printError(String message) {
+ appendLine("# Error: " + message);
+ }
+
+ abstract void printField(DexClass dexClass, DexField field);
+
+ abstract void printMethod(DexEncodedMethod encodedMethod, String typeName);
+
+ void printNameAndReturn(DexEncodedMethod encodedMethod) {
+ if (encodedMethod.accessFlags.isConstructor()) {
+ printConstructorName(encodedMethod);
+ } else {
+ DexMethod method = encodedMethod.method;
+ append(method.proto.returnType.toSourceString());
+ append(" ");
+ append(method.name.toSourceString());
+ }
+ }
+
+ abstract void printTypeHeader(DexClass dexClass);
+
+ abstract void printTypeFooter();
+
+ int print(
+ DexApplication application,
+ Set<DexType> types,
+ Map<DexType, Set<DexMethod>> methods,
+ Map<DexType, Set<DexField>> fields) {
+ int errors = 0;
+ List<DexType> sortedTypes = new ArrayList<>(types);
+ sortedTypes.sort(Comparator.comparing(DexType::toSourceString));
+ for (DexType type : sortedTypes) {
+ DexClass dexClass = application.definitionFor(type);
+ if (dexClass == null) {
+ printError("Could not find definition for type " + type.toSourceString());
+ errors++;
continue;
}
- methodDefinitions.add(getMethodSourceString(encodedMethod));
+ printTypeHeader(dexClass);
+ List<DexEncodedMethod> methodDefinitions = new ArrayList<>(methods.size());
+ for (DexMethod method : methods.get(type)) {
+ DexEncodedMethod encodedMethod = dexClass.lookupMethod(method);
+ if (encodedMethod == null) {
+ printError("Could not find definition for method " + method.toSourceString());
+ errors++;
+ continue;
+ }
+ methodDefinitions.add(encodedMethod);
+ }
+ methodDefinitions.sort(Comparator.comparing(x -> x.method.name.toSourceString()));
+ for (DexEncodedMethod encodedMethod : methodDefinitions) {
+ printMethod(encodedMethod, dexClass.type.toSourceString());
+ }
+ List<DexField> sortedFields = new ArrayList<>(fields.get(type));
+ sortedFields.sort(Comparator.comparing(DexField::toSourceString));
+ for (DexField field : sortedFields) {
+ printField(dexClass, field);
+ }
+ printTypeFooter();
}
- methodDefinitions.sort(Comparator.naturalOrder());
- for (String encodedMethod : methodDefinitions) {
- out.println(typeName + ": " + encodedMethod);
- }
- List<DexField> fields = new ArrayList<>(this.fields.get(type));
- fields.sort(Comparator.comparing(DexField::toSourceString));
- for (DexField field : fields) {
- out.println(
- typeName + ": " + field.type.toSourceString() + " " + field.name.toSourceString());
- }
+ return errors;
}
}
- private void error(String message) {
- out.println("# Error: " + message);
- errors += 1;
- }
+ private static class DefaultPrinter extends Printer {
- private static String getMethodSourceString(DexEncodedMethod encodedMethod) {
- DexMethod method = encodedMethod.method;
- StringBuilder builder = new StringBuilder();
- if (encodedMethod.accessFlags.isConstructor()) {
+ @Override
+ public void printConstructorName(DexEncodedMethod encodedMethod) {
if (encodedMethod.accessFlags.isStatic()) {
- builder.append("<clinit>");
+ append("<clinit>");
} else {
- String holderName = method.holder.toSourceString();
+ String holderName = encodedMethod.method.holder.toSourceString();
String constructorName = holderName.substring(holderName.lastIndexOf('.') + 1);
- builder.append(constructorName);
+ append(constructorName);
}
- } else {
- builder
- .append(method.proto.returnType.toSourceString())
- .append(" ")
- .append(method.name.toSourceString());
}
- builder.append("(");
- for (int i = 0; i < method.getArity(); i++) {
- if (i != 0) {
- builder.append(",");
+
+ @Override
+ void printMethod(DexEncodedMethod encodedMethod, String typeName) {
+ append(typeName + ": ");
+ printNameAndReturn(encodedMethod);
+ printArguments(encodedMethod.method);
+ appendLine("");
+ }
+
+ @Override
+ void printTypeHeader(DexClass dexClass) {
+ appendLine(dexClass.type.toSourceString());
+ }
+
+ @Override
+ void printTypeFooter() {}
+
+ @Override
+ void printField(DexClass dexClass, DexField field) {
+ appendLine(
+ dexClass.type.toSourceString()
+ + ": "
+ + field.type.toSourceString()
+ + " "
+ + field.name.toString());
+ }
+ }
+
+ private static class KeepPrinter extends Printer {
+
+ @Override
+ public void printTypeHeader(DexClass dexClass) {
+ if (dexClass.isInterface()) {
+ append("-keep interface " + dexClass.type.toSourceString() + " {\n");
+ } else if (dexClass.accessFlags.isEnum()) {
+ append("-keep enum " + dexClass.type.toSourceString() + " {\n");
+ } else {
+ append("-keep class " + dexClass.type.toSourceString() + " {\n");
}
- builder.append(method.proto.parameters.values[i].toSourceString());
}
- builder.append(")");
- return builder.toString();
+
+ @Override
+ public void printConstructorName(DexEncodedMethod encodedMethod) {
+ append("<init>");
+ }
+
+ @Override
+ public void printField(DexClass dexClass, DexField field) {
+ append(" " + field.type.toSourceString() + " " + field.name.toString() + ";\n");
+ }
+
+ @Override
+ public void printMethod(DexEncodedMethod encodedMethod, String typeName) {
+ append(" ");
+ if (encodedMethod.isPublicMethod()) {
+ append("public ");
+ } else if (encodedMethod.isPrivateMethod()) {
+ append("private ");
+ }
+ if (encodedMethod.isStatic()) {
+ append("static ");
+ }
+ printNameAndReturn(encodedMethod);
+ printArguments(encodedMethod.method);
+ appendLine(";");
+ }
+
+ @Override
+ public void printTypeFooter() {
+ appendLine("}");
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 05e7359..70c0f40 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -290,7 +290,9 @@
options.getProguardConfiguration().getDontWarnPatterns(),
executorService,
timing));
- // assert rootSet.verifyKeptMethodsAreTargetedAndLive(appView.appInfo().withLiveness());
+ assert rootSet.verifyKeptFieldsAreAccessedAndLive(appView.appInfo().withLiveness());
+ assert rootSet.verifyKeptMethodsAreTargetedAndLive(appView.appInfo().withLiveness());
+ assert rootSet.verifyKeptTypesAreLive(appView.appInfo().withLiveness());
if (options.getProguardConfiguration().isPrintSeeds()) {
ByteArrayOutputStream bytes = new ByteArrayOutputStream();
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 6ee0f6e..0434f66 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,7 +41,6 @@
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;
@@ -120,7 +119,6 @@
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;
@@ -185,8 +183,6 @@
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 =
@@ -371,12 +367,6 @@
}
}
- private void synthesizeJava8UtilityClass(Builder<?> builder) {
- if (java8MethodRewriter != null) {
- java8MethodRewriter.synthesizeUtilityClass(builder, options);
- }
- }
-
private void processCovariantReturnTypeAnnotations(Builder<?> builder) {
if (covariantReturnTypeAnnotationTransformer != null) {
covariantReturnTypeAnnotationTransformer.process(builder);
@@ -397,7 +387,6 @@
synthesizeLambdaClasses(builder, executor);
desugarInterfaceMethods(builder, ExcludeDexResources, executor);
synthesizeTwrCloseResourceUtilityClass(builder);
- synthesizeJava8UtilityClass(builder);
processCovariantReturnTypeAnnotations(builder);
handleSynthesizedClassMapping(builder);
@@ -584,10 +573,11 @@
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);
@@ -1020,9 +1010,6 @@
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
deleted file mode 100644
index 3cb741a..0000000
--- a/src/main/java/com/android/tools/r8/ir/desugar/Java8MethodRewriter.java
+++ /dev/null
@@ -1,262 +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.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.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.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<DexProgramClass> referencingClasses = 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);
- referencingClasses.add(
- converter.appInfo.definitionFor(code.method.method.holder).asProgramClass());
- }
- }
-
- public void synthesizeUtilityClass(Builder<?> builder, InternalOptions options) {
- if (referencingClasses.isEmpty()) {
- return;
- }
-
- 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, String desc) {
- super(options, method, methodName, desc);
- }
-
- public static IntegerMethods hashCodeCode(InternalOptions options, DexMethod method) {
- return new IntegerMethods(options, method, "hashCodeImpl", "(I)I");
- }
-
- public static IntegerMethods maxCode(InternalOptions options, DexMethod method) {
- return new IntegerMethods(options, method, "maxImpl", "(II)I");
- }
-
- public static int hashCodeImpl(int value) {
- return Integer.valueOf(value).hashCode();
- }
-
- public static int maxImpl(int a, int b) {
- return java.lang.Math.max(a, b);
- }
- }
-
- private static final class DoubleMethods extends TemplateMethodCode {
- DoubleMethods(InternalOptions options, DexMethod method, String methodName, String desc) {
- super(options, method, methodName, desc);
- }
-
- public static DoubleMethods hashCodeCode(InternalOptions options, DexMethod method) {
- return new DoubleMethods(options, method, "hashCodeImpl", "(D)I");
- }
-
- public static DoubleMethods maxCode(InternalOptions options, DexMethod method) {
- return new DoubleMethods(options, method, "maxImpl", "(DD)D");
- }
-
- public static int hashCodeImpl(double value) {
- return Double.valueOf(value).hashCode();
- }
-
- public static double maxImpl(double a, double b) {
- return java.lang.Math.max(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));
-
- // 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));
-
- }
-
- 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/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index c579500..169f8a3 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -1153,9 +1153,9 @@
private void markDirectStaticOrConstructorMethodAsLive(
DexEncodedMethod encodedMethod, KeepReason reason) {
assert encodedMethod != null;
+ markMethodAsTargeted(encodedMethod, reason);
if (!liveMethods.contains(encodedMethod)) {
markTypeAsLive(encodedMethod.method.holder);
- markMethodAsTargeted(encodedMethod, reason);
if (Log.ENABLED) {
Log.verbose(getClass(), "Method `%s` has become live due to direct invoke",
encodedMethod.method);
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 5bf6b4c..374553a 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -1021,6 +1021,24 @@
.unmodifiableMap(dependentNoShrinking.getOrDefault(item, Collections.emptyMap()));
}
+ public boolean verifyKeptFieldsAreAccessedAndLive(AppInfoWithLiveness appInfo) {
+ for (DexDefinition definition : noShrinking.keySet()) {
+ if (definition.isDexEncodedField()) {
+ DexEncodedField field = definition.asDexEncodedField();
+ if (field.isStatic() || isKeptDirectlyOrIndirectly(field.field.clazz, appInfo)) {
+ // TODO(b/121354886): Enable asserts for reads and writes.
+ /*assert appInfo.fieldsRead.contains(field.field)
+ : "Expected kept field `" + field.field.toSourceString() + "` to be read";
+ assert appInfo.fieldsWritten.contains(field.field)
+ : "Expected kept field `" + field.field.toSourceString() + "` to be written";*/
+ assert appInfo.liveFields.contains(field.field)
+ : "Expected kept field `" + field.field.toSourceString() + "` to be live";
+ }
+ }
+ }
+ return true;
+ }
+
public boolean verifyKeptMethodsAreTargetedAndLive(AppInfoWithLiveness appInfo) {
for (DexDefinition definition : noShrinking.keySet()) {
if (definition.isDexEncodedMethod()) {
@@ -1040,6 +1058,17 @@
return true;
}
+ public boolean verifyKeptTypesAreLive(AppInfoWithLiveness appInfo) {
+ for (DexDefinition definition : noShrinking.keySet()) {
+ if (definition.isDexClass()) {
+ DexClass clazz = definition.asDexClass();
+ assert appInfo.liveTypes.contains(clazz.type)
+ : "Expected kept type `" + clazz.type.toSourceString() + "` to be live";
+ }
+ }
+ return true;
+ }
+
private boolean isKeptDirectlyOrIndirectly(DexType type, AppInfoWithLiveness appInfo) {
DexClass clazz = appInfo.definitionFor(type);
if (clazz == null) {
diff --git a/src/test/java/com/android/tools/r8/Dummy.java b/src/test/java/com/android/tools/r8/Dummy.java
new file mode 100644
index 0000000..caf8bb9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/Dummy.java
@@ -0,0 +1,23 @@
+// 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;
+
+import org.junit.Test;
+
+public class Dummy extends TestBase {
+
+ @Test
+ public void testKeep() throws Exception {
+ PrintUses.main(
+ ToolHelper.getJava8RuntimeJar().toString(),
+ "build/libs/r8_without_deps.jar",
+ "build/libs/r8tests.jar");
+ PrintUses.main(
+ "--keeprules",
+ ToolHelper.getJava8RuntimeJar().toString(),
+ "build/libs/r8_without_deps.jar",
+ "build/libs/r8tests.jar");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java b/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
deleted file mode 100644
index c4632d7..0000000
--- a/src/test/java/com/android/tools/r8/desugar/Java8MethodsTest.java
+++ /dev/null
@@ -1,37 +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.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) {
- System.out.println(Integer.hashCode(42));
- System.out.println(Integer.max(42, 3));
- System.out.println(Double.hashCode(42.0));
- System.out.println(Double.max(42.0, 43.0));
- }
- }
-}