diff options
author | Ivan Gavrilovic <gavra@google.com> | 2017-07-13 11:09:11 +0100 |
---|---|---|
committer | Ivan Gavrilovic <gavra@google.com> | 2017-07-13 11:12:48 +0100 |
commit | e60b2c831ad5de7916ec696e1069850578f64b04 (patch) | |
tree | 65af4d76ce0f547cffd9d0e415fe1fedd2bb7337 /src/main/java/com/android/tools/r8 | |
parent | 8842c41758db478ebc54437f583367750cd18378 (diff) | |
parent | 89abf02c23101825145e7fff1f7ae7c017fadc27 (diff) | |
download | r8-e60b2c831ad5de7916ec696e1069850578f64b04.tar.gz |
Merge remote-tracking branch 'aosp/upstream-mirror' into master
* aosp/upstream-mirror:
Use equals method from CanonicalizedDexItem
Do not use a subclass in a static field initializer.
Support continuous stepping in debug tests
Fix keep rule debugging support.
-printusage part I: parse -printusage [file].
Do not obfuscate unknown types in protos.
Enable Art tests using Java 8 features
Add support for generation keep rules from maindexlist.
Write unaligned sections before aligned sections
Test: mma -j external/r8
Change-Id: Ic2a572ff04de9cbafe48a212d77c6ad7658f855d
Diffstat (limited to 'src/main/java/com/android/tools/r8')
19 files changed, 175 insertions, 146 deletions
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java index a71091252..aed488649 100644 --- a/src/main/java/com/android/tools/r8/R8Command.java +++ b/src/main/java/com/android/tools/r8/R8Command.java @@ -363,6 +363,9 @@ public class R8Command extends BaseCommand { internal.skipMinification = !useMinification(); assert internal.useTreeShaking; internal.useTreeShaking = useTreeShaking(); + assert !internal.printUsage; + internal.printUsage = proguardConfiguration.isPrintUsage(); + internal.printUsageFile = proguardConfiguration.getPrintUsageFile(); assert !internal.ignoreMissingClasses; internal.ignoreMissingClasses = ignoreMissingClasses; diff --git a/src/main/java/com/android/tools/r8/ReadMainDexList.java b/src/main/java/com/android/tools/r8/ReadMainDexList.java index 3a76c1fbb..a0c47895e 100644 --- a/src/main/java/com/android/tools/r8/ReadMainDexList.java +++ b/src/main/java/com/android/tools/r8/ReadMainDexList.java @@ -6,7 +6,11 @@ package com.android.tools.r8; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.naming.ProguardMapReader; import com.android.tools.r8.utils.FileUtils; +import com.google.common.collect.Iterators; +import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Iterator; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -20,8 +24,12 @@ public class ReadMainDexList { return name.endsWith(DOT_CLASS) ? name.substring(0, name.length() - DOT_CLASS.length()) : name; } - private String addDotClass(String name) { - return name + DOT_CLASS; + private String toClassFilePath(String name) { + return name.replace('.', '/') + DOT_CLASS; + } + + private String toKeepRule(String className) { + return "-keep class " + className + " {}"; } private String deobfuscateClassName(String name, ClassNameMapper mapper) { @@ -32,21 +40,31 @@ public class ReadMainDexList { } private void run(String[] args) throws Exception { - if (args.length != 1 && args.length != 2) { - System.out.println("Usage: command <main_dex_list> [<proguard_map>]"); + if (args.length < 1 || args.length > 3) { + System.out.println("Usage: command [-k] <main_dex_list> [<proguard_map>]"); System.exit(0); } + Iterator<String> arguments = Iterators.forArray(args); + Function<String, String> outputGenerator; + String arg = arguments.next(); + if (arg.equals("-k")) { + outputGenerator = this::toKeepRule; + arg = arguments.next(); + } else { + outputGenerator = this::toClassFilePath; + } + Path mainDexList = Paths.get(arg); + final ClassNameMapper mapper = - args.length == 2 ? ProguardMapReader.mapperFromFile(Paths.get(args[1])) : null; + arguments.hasNext() ? ProguardMapReader.mapperFromFile(Paths.get(arguments.next())) : null; - FileUtils.readTextFile(Paths.get(args[0])) + FileUtils.readTextFile(mainDexList) .stream() .map(this::stripDotClass) .map(name -> name.replace('/', '.')) .map(name -> deobfuscateClassName(name, mapper)) - .map(name -> name.replace('.', '/')) - .map(this::addDotClass) + .map(outputGenerator) .sorted() .collect(Collectors.toList()) .forEach(System.out::println); diff --git a/src/main/java/com/android/tools/r8/dex/DexFileReader.java b/src/main/java/com/android/tools/r8/dex/DexFileReader.java index a0644948f..1c3707337 100644 --- a/src/main/java/com/android/tools/r8/dex/DexFileReader.java +++ b/src/main/java/com/android/tools/r8/dex/DexFileReader.java @@ -47,6 +47,7 @@ import com.android.tools.r8.graph.DexTypeList; import com.android.tools.r8.graph.DexValue; import com.android.tools.r8.graph.DexValue.DexValueMethodHandle; import com.android.tools.r8.graph.DexValue.DexValueMethodType; +import com.android.tools.r8.graph.DexValue.DexValueNull; import com.android.tools.r8.graph.DexValue.DexValueString; import com.android.tools.r8.graph.OffsetToObjectMapping; import com.android.tools.r8.logging.Log; @@ -226,7 +227,7 @@ public class DexFileReader { } case DexValue.VALUE_NULL: { assert valueArg == 0; - return DexValue.NULL; + return DexValueNull.NULL; } case DexValue.VALUE_BOOLEAN: { // 0 is false, and 1 is true. diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java index 6c6c3e16a..00eea7cb0 100644 --- a/src/main/java/com/android/tools/r8/dex/FileWriter.java +++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java @@ -215,18 +215,16 @@ public class FileWriter { this::writeStringData); writeItems(mixedSectionOffsets.getAnnotations(), layout::setAnnotationsOffset, this::writeAnnotation); + writeItems(mixedSectionOffsets.getClassesWithData(), layout::setClassDataOffset, + this::writeClassData); + writeItems(mixedSectionOffsets.getEncodedArrays(), layout::setEncodedArrarysOffset, + this::writeEncodedArray); writeItems(mixedSectionOffsets.getAnnotationSets(), layout::setAnnotationSetsOffset, this::writeAnnotationSet, 4); writeItems(mixedSectionOffsets.getAnnotationSetRefLists(), layout::setAnnotationSetRefListsOffset, this::writeAnnotationSetRefList, 4); - // Write the annotation directories. writeItems(mixedSectionOffsets.getAnnotationDirectories(), layout::setAnnotationDirectoriesOffset, this::writeAnnotationDirectory, 4); - // Write the rest. - writeItems(mixedSectionOffsets.getClassesWithData(), layout::setClassDataOffset, - this::writeClassData); - writeItems(mixedSectionOffsets.getEncodedArrays(), layout::setEncodedArrarysOffset, - this::writeEncodedArray); // Add the map at the end layout.setMapOffset(dest.align(4)); @@ -760,6 +758,10 @@ public class FileWriter { mixedSectionOffsets.getStringData().size()); size += writeMapItem(Constants.TYPE_ANNOTATION_ITEM, layout.getAnnotationsOffset(), mixedSectionOffsets.getAnnotations().size()); + size += writeMapItem(Constants.TYPE_CLASS_DATA_ITEM, layout.getClassDataOffset(), + mixedSectionOffsets.getClassesWithData().size()); + size += writeMapItem(Constants.TYPE_ENCODED_ARRAY_ITEM, layout.getEncodedArrarysOffset(), + mixedSectionOffsets.getEncodedArrays().size()); size += writeMapItem(Constants.TYPE_ANNOTATION_SET_ITEM, layout.getAnnotationSetsOffset(), mixedSectionOffsets.getAnnotationSets().size()); size += writeMapItem(Constants.TYPE_ANNOTATION_SET_REF_LIST, @@ -768,10 +770,6 @@ public class FileWriter { size += writeMapItem(Constants.TYPE_ANNOTATIONS_DIRECTORY_ITEM, layout.getAnnotationDirectoriesOffset(), mixedSectionOffsets.getAnnotationDirectories().size()); - size += writeMapItem(Constants.TYPE_CLASS_DATA_ITEM, layout.getClassDataOffset(), - mixedSectionOffsets.getClassesWithData().size()); - size += writeMapItem(Constants.TYPE_ENCODED_ARRAY_ITEM, layout.getEncodedArrarysOffset(), - mixedSectionOffsets.getEncodedArrays().size()); size += writeMapItem(Constants.TYPE_MAP_LIST, layout.getMapOffset(), 1); dest.moveTo(startOfMap); dest.putInt(size); diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java index 66d977418..55aa9868a 100644 --- a/src/main/java/com/android/tools/r8/graph/DexAnnotation.java +++ b/src/main/java/com/android/tools/r8/graph/DexAnnotation.java @@ -9,6 +9,7 @@ import com.android.tools.r8.graph.DexValue.DexValueAnnotation; import com.android.tools.r8.graph.DexValue.DexValueArray; import com.android.tools.r8.graph.DexValue.DexValueInt; import com.android.tools.r8.graph.DexValue.DexValueMethod; +import com.android.tools.r8.graph.DexValue.DexValueNull; import com.android.tools.r8.graph.DexValue.DexValueString; import com.android.tools.r8.graph.DexValue.DexValueType; import java.util.ArrayList; @@ -111,7 +112,7 @@ public class DexAnnotation extends DexItem { new DexAnnotationElement( factory.createString("name"), (clazz == null) - ? DexValue.NULL + ? DexValueNull.NULL : new DexValueString(factory.createString(clazz))) })); } diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java index 3df2fabe7..c8fbbeadf 100644 --- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java +++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java @@ -12,9 +12,12 @@ import com.android.tools.r8.code.Const; import com.android.tools.r8.code.ConstString; import com.android.tools.r8.code.ConstStringJumbo; import com.android.tools.r8.code.Instruction; +import com.android.tools.r8.code.InvokeDirect; import com.android.tools.r8.code.InvokeStatic; +import com.android.tools.r8.code.InvokeSuper; import com.android.tools.r8.code.NewInstance; import com.android.tools.r8.code.Throw; +import com.android.tools.r8.dex.Constants; import com.android.tools.r8.dex.IndexedItemCollection; import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.ir.code.IRCode; @@ -30,6 +33,7 @@ import com.android.tools.r8.logging.Log; import com.android.tools.r8.naming.ClassNameMapper; import com.android.tools.r8.naming.MemberNaming.MethodSignature; import com.android.tools.r8.naming.MemberNaming.Signature; +import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness; import com.android.tools.r8.utils.InternalOptions; public class DexEncodedMethod extends KeyedDexItem<DexMethod> { @@ -238,7 +242,7 @@ public class DexEncodedMethod extends KeyedDexItem<DexMethod> { * templates might incur a size overhead. */ private DexCode generateCodeFromTemplate( - int numberOfRegisters, int outRegisters, Instruction[] instructions) { + int numberOfRegisters, int outRegisters, Instruction... instructions) { int offset = 0; for (Instruction instruction : instructions) { assert !(instruction instanceof ConstString); @@ -276,21 +280,33 @@ public class DexEncodedMethod extends KeyedDexItem<DexMethod> { .createMethod(itemFactory.createType("Landroid/util/Log;"), proto, itemFactory.createString("e")); DexType exceptionType = itemFactory.createType("Ljava/lang/RuntimeException;"); - DexType[] exceptionArgs = {exceptionType, itemFactory.stringType}; - DexMethod initMethod = itemFactory - .createMethod(exceptionType, itemFactory.createProto(itemFactory.voidType, exceptionArgs), + DexMethod exceptionInitMethod = itemFactory + .createMethod(exceptionType, itemFactory.createProto(itemFactory.voidType, + itemFactory.stringType), itemFactory.constructorMethodName); - // These methods might not get registered for jumbo string processing, therefore we always - // use the jumbo string encoding for the const string instruction. - Instruction insn[] = { - new ConstStringJumbo(0, tag), - new ConstStringJumbo(1, message), - new InvokeStatic(2, logMethod, 0, 1, 0, 0, 0), - new NewInstance(0, exceptionType), - new InvokeStatic(2, initMethod, 0, 1, 0, 0, 0), - new Throw(0) - }; - DexCode code = generateCodeFromTemplate(2, 2, insn); + DexCode code; + if (accessFlags.isConstructor() && !accessFlags.isStatic()) { + // The Java VM Spec requires that a constructor calls an initializer from the super class + // or another constructor from the current class. For simplicity we do the latter by just + // calling outself. This is ok, as the constructor always throws before the recursive call. + code = generateCodeFromTemplate(3, 2, new ConstStringJumbo(0, tag), + new ConstStringJumbo(1, message), + new InvokeStatic(2, logMethod, 0, 1, 0, 0, 0), + new NewInstance(0, exceptionType), + new InvokeDirect(2, exceptionInitMethod, 0, 1, 0, 0, 0), + new Throw(0), + new InvokeDirect(1, method, 2, 0, 0, 0, 0)); + + } else { + // These methods might not get registered for jumbo string processing, therefore we always + // use the jumbo string encoding for the const string instruction. + code = generateCodeFromTemplate(2, 2, new ConstStringJumbo(0, tag), + new ConstStringJumbo(1, message), + new InvokeStatic(2, logMethod, 0, 1, 0, 0, 0), + new NewInstance(0, exceptionType), + new InvokeDirect(2, exceptionInitMethod, 0, 1, 0, 0, 0), + new Throw(0)); + } Builder builder = builder(this); builder.setCode(code); return builder.build(); diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java index 984215b80..5dff4b432 100644 --- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java +++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java @@ -222,32 +222,22 @@ public class DexItemFactory { DexString toStringMethodName = createString("toString"); - appendBoolean = - createMethod(receiver, createProto(receiver, new DexType[]{booleanType}), append); - appendChar = createMethod(receiver, createProto(receiver, new DexType[]{charType}), append); - appendCharArray = - createMethod(receiver, createProto(receiver, new DexType[]{charArrayType}), append); + appendBoolean = createMethod(receiver, createProto(receiver, booleanType), append); + appendChar = createMethod(receiver, createProto(receiver, charType), append); + appendCharArray = createMethod(receiver, createProto(receiver, charArrayType), append); appendSubCharArray = - createMethod(receiver, - createProto(receiver, new DexType[]{charArrayType, intType, intType}), append); - appendCharSequence = - createMethod(receiver, createProto(receiver, new DexType[]{charSequenceType}), append); + createMethod(receiver, createProto(receiver, charArrayType, intType, intType), append); + appendCharSequence = createMethod(receiver, createProto(receiver, charSequenceType), append); appendSubCharSequence = - createMethod(receiver, - createProto(receiver, new DexType[]{charSequenceType, intType, intType}), append); - appendInt = createMethod(receiver, createProto(receiver, new DexType[]{intType}), append); - appendDouble = - createMethod(receiver, createProto(receiver, new DexType[]{doubleType}), append); - appendFloat = createMethod(receiver, createProto(receiver, new DexType[]{floatType}), append); - appendLong = createMethod(receiver, createProto(receiver, new DexType[]{longType}), append); - appendObject = - createMethod(receiver, createProto(receiver, new DexType[]{objectType}), append); - appendString = - createMethod(receiver, createProto(receiver, new DexType[]{stringType}), append); - appendStringBuffer = - createMethod(receiver, createProto(receiver, new DexType[]{sbufType}), append); - toString = - createMethod(receiver, createProto(stringType, DexType.EMPTY_ARRAY), toStringMethodName); + createMethod(receiver, createProto(receiver, charSequenceType, intType, intType), append); + appendInt = createMethod(receiver, createProto(receiver, intType), append); + appendDouble = createMethod(receiver, createProto(receiver, doubleType), append); + appendFloat = createMethod(receiver, createProto(receiver, floatType), append); + appendLong = createMethod(receiver, createProto(receiver, longType), append); + appendObject = createMethod(receiver, createProto(receiver, objectType), append); + appendString = createMethod(receiver, createProto(receiver, stringType), append); + appendStringBuffer = createMethod(receiver, createProto(receiver, sbufType), append); + toString = createMethod(receiver, createProto(stringType), toStringMethodName); } public void forEachAppendMethod(Consumer<DexMethod> consumer) { @@ -322,7 +312,7 @@ public class DexItemFactory { parameters.length == 0 ? DexTypeList.empty() : new DexTypeList(parameters)); } - public DexProto createProto(DexType returnType, DexType[] parameters) { + public DexProto createProto(DexType returnType, DexType... parameters) { return createProto(createShorty(returnType, parameters), returnType, parameters); } diff --git a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java index e59e7c97a..d2237352f 100644 --- a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java +++ b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java @@ -132,7 +132,7 @@ public class DexMethodHandle extends IndexedDexItem { public boolean computeEquals(Object other) { if (other instanceof DexMethodHandle) { DexMethodHandle o = (DexMethodHandle) other; - return type.equals(o.type) && fieldOrMethod.computeEquals(o.fieldOrMethod); + return type.equals(o.type) && fieldOrMethod.equals(o.fieldOrMethod); } return false; } diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java index 4d3d8cb25..234773f96 100644 --- a/src/main/java/com/android/tools/r8/graph/DexType.java +++ b/src/main/java/com/android/tools/r8/graph/DexType.java @@ -19,8 +19,6 @@ import java.util.function.Function; public class DexType extends IndexedDexItem implements PresortedComparable<DexType> { - public static final DexType[] EMPTY_ARRAY = new DexType[]{}; - private final static int ROOT_LEVEL = 0; private final static int UNKNOWN_LEVEL = -1; private final static int INTERFACE_LEVEL = -2; diff --git a/src/main/java/com/android/tools/r8/graph/DexValue.java b/src/main/java/com/android/tools/r8/graph/DexValue.java index 5430d6e1e..a0cfa7c3a 100644 --- a/src/main/java/com/android/tools/r8/graph/DexValue.java +++ b/src/main/java/com/android/tools/r8/graph/DexValue.java @@ -36,8 +36,6 @@ public abstract class DexValue extends DexItem { public static final byte VALUE_NULL = 0x1e; public static final byte VALUE_BOOLEAN = 0x1f; - public static final DexValue NULL = new DexValueNull(); - private static void writeHeader(byte type, int arg, DexOutputBuffer dest) { dest.putByte((byte) ((arg << 5) | type)); } @@ -87,7 +85,7 @@ public abstract class DexValue extends DexItem { return DexValueDouble.DEFAULT; } if (type.isArrayType() || type.isClassType()) { - return DexValue.NULL; + return DexValueNull.NULL; } throw new Unreachable("No default value for unexpected type " + type); } @@ -688,7 +686,9 @@ public abstract class DexValue extends DexItem { static public class DexValueNull extends SimpleDexValue { - // See DexValue.NULL + public static final DexValue NULL = new DexValueNull(); + + // See DexValueNull.NULL private DexValueNull() { } diff --git a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java index 59f187f0c..ce38bc967 100644 --- a/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java +++ b/src/main/java/com/android/tools/r8/graph/JarClassFileReader.java @@ -20,6 +20,7 @@ import com.android.tools.r8.graph.DexValue.DexValueEnum; import com.android.tools.r8.graph.DexValue.DexValueFloat; import com.android.tools.r8.graph.DexValue.DexValueInt; import com.android.tools.r8.graph.DexValue.DexValueLong; +import com.android.tools.r8.graph.DexValue.DexValueNull; import com.android.tools.r8.graph.DexValue.DexValueShort; import com.android.tools.r8.graph.DexValue.DexValueString; import com.android.tools.r8.graph.DexValue.DexValueType; @@ -699,7 +700,7 @@ public class JarClassFileReader { private DexValue getDexValue(Object value) { if (value == null) { - return DexValue.NULL; + return DexValueNull.NULL; } if (value instanceof Byte) { return DexValueByte.create((Byte) value); diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java index cb518a3d0..c2600b4e4 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java @@ -23,7 +23,7 @@ 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.DexValue; +import com.android.tools.r8.graph.DexValue.DexValueNull; import com.android.tools.r8.ir.code.Invoke; import com.android.tools.r8.ir.synthetic.SynthesizedCode; import java.util.List; @@ -219,7 +219,7 @@ final class LambdaClass { new DexAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_FINAL | Constants.ACC_SYNTHETIC | Constants.ACC_STATIC), DexAnnotationSet.empty(), - DexValue.NULL); + DexValueNull.NULL); return fields; } diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java index 2355e5eb5..9ec776f47 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaMainMethodSourceCode.java @@ -4,8 +4,6 @@ package com.android.tools.r8.ir.desugar; -import static com.android.tools.r8.ir.desugar.LambdaRewriter.EMPTY_TYPE_ARRAY; - import com.android.tools.r8.errors.Unreachable; import com.android.tools.r8.graph.DexField; import com.android.tools.r8.graph.DexItemFactory; @@ -421,28 +419,28 @@ final class LambdaMainMethodSourceCode extends SynthesizedLambdaSourceCode { DexProto proto; switch (primitive) { case 'Z': // byte - proto = factory.createProto(factory.booleanType, EMPTY_TYPE_ARRAY); + proto = factory.createProto(factory.booleanType); return factory.createMethod(boxType, proto, factory.unboxBooleanMethodName); case 'B': // byte - proto = factory.createProto(factory.byteType, EMPTY_TYPE_ARRAY); + proto = factory.createProto(factory.byteType); return factory.createMethod(boxType, proto, factory.unboxByteMethodName); case 'S': // short - proto = factory.createProto(factory.shortType, EMPTY_TYPE_ARRAY); + proto = factory.createProto(factory.shortType); return factory.createMethod(boxType, proto, factory.unboxShortMethodName); case 'C': // char - proto = factory.createProto(factory.charType, EMPTY_TYPE_ARRAY); + proto = factory.createProto(factory.charType); return factory.createMethod(boxType, proto, factory.unboxCharMethodName); case 'I': // int - proto = factory.createProto(factory.intType, EMPTY_TYPE_ARRAY); + proto = factory.createProto(factory.intType); return factory.createMethod(boxType, proto, factory.unboxIntMethodName); case 'J': // long - proto = factory.createProto(factory.longType, EMPTY_TYPE_ARRAY); + proto = factory.createProto(factory.longType); return factory.createMethod(boxType, proto, factory.unboxLongMethodName); case 'F': // float - proto = factory.createProto(factory.floatType, EMPTY_TYPE_ARRAY); + proto = factory.createProto(factory.floatType); return factory.createMethod(boxType, proto, factory.unboxFloatMethodName); case 'D': // double - proto = factory.createProto(factory.doubleType, EMPTY_TYPE_ARRAY); + proto = factory.createProto(factory.doubleType); return factory.createMethod(boxType, proto, factory.unboxDoubleMethodName); default: throw new Unreachable("Invalid primitive type descriptor: " + primitive); diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java index 10908f038..7d3bc336d 100644 --- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java @@ -54,7 +54,6 @@ public class LambdaRewriter { static final String LAMBDA_CLASS_NAME_PREFIX = "-$$Lambda$"; static final String EXPECTED_LAMBDA_METHOD_PREFIX = "lambda$"; - static final DexType[] EMPTY_TYPE_ARRAY = new DexType[0]; static final String LAMBDA_INSTANCE_FIELD_NAME = "INSTANCE"; final IRConverter converter; @@ -103,20 +102,17 @@ public class LambdaRewriter { DexType objectArrayType = factory.createType(OBJECT_ARRAY_TYPE_DESCR); this.metafactoryMethod = factory.createMethod(metafactoryType, - factory.createProto(callSiteType, new DexType[] { - lookupType, factory.stringType, methodTypeType, - methodTypeType, methodHandleType, methodTypeType - }), + factory.createProto(callSiteType, lookupType, factory.stringType, methodTypeType, + methodTypeType, methodHandleType, methodTypeType), factory.createString(METAFACTORY_METHOD_NAME)); this.metafactoryAltMethod = factory.createMethod(metafactoryType, - factory.createProto(callSiteType, new DexType[] { - lookupType, factory.stringType, methodTypeType, objectArrayType - }), + factory.createProto(callSiteType, lookupType, factory.stringType, methodTypeType, + objectArrayType), factory.createString(METAFACTORY_ALT_METHOD_NAME)); this.constructorName = factory.createString(Constants.INSTANCE_INITIALIZER_NAME); - DexProto initProto = factory.createProto(factory.voidType, EMPTY_TYPE_ARRAY); + DexProto initProto = factory.createProto(factory.voidType); this.objectInitMethod = factory.createMethod(factory.objectType, initProto, constructorName); this.classConstructorName = factory.createString(Constants.CLASS_INITIALIZER_NAME); this.instanceFieldName = factory.createString(LAMBDA_INSTANCE_FIELD_NAME); @@ -124,7 +120,7 @@ public class LambdaRewriter { this.deserializeLambdaMethodName = factory.createString(DESERIALIZE_LAMBDA_METHOD_NAME); this.deserializeLambdaMethodProto = factory.createProto( - factory.objectType, new DexType[] { factory.createType(SERIALIZED_LAMBDA_TYPE_DESCR) }); + factory.objectType, factory.createType(SERIALIZED_LAMBDA_TYPE_DESCR)); } /** diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java index de8033808..7c12590b3 100644 --- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java +++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java @@ -22,16 +22,6 @@ import java.util.Set; public class ClassNameMinifier { - /** - * We ban classes from these prefixes from minification. This is needed as some classes - * in the android sdk are given a @hide annotation, which will remove them from the - * sdk we tree-shake and minify against. Thus, the class will not be available and hence - * we won't find out that it is a library class. - * To save space, we by default minify classes we do not have an implementation for. - */ - private static final Set<String> BANNED_CLASS_PREFIXES = ImmutableSet - .of("Ljava", "Landroid", "Ldalvik"); - private final AppInfoWithLiveness appInfo; private final RootSet rootSet; private final String packagePrefix; @@ -65,17 +55,13 @@ public class ClassNameMinifier { renaming.put(clazz.type, state.nextTypeName()); } } - renameTypesInProtosOf(appInfo.staticInvokes); - renameTypesInProtosOf(appInfo.superInvokes); - renameTypesInProtosOf(appInfo.directInvokes); - renameTypesInProtosOf(appInfo.virtualInvokes); appInfo.dexItemFactory.forAllTypes(this::renameArrayTypeIfNeeded); return Collections.unmodifiableMap(renaming); } private String getPackageNameFor(DexClass clazz) { - if (packagePrefix == null || rootSet.keepPackageName.contains(clazz)) { + if ((packagePrefix == null) || rootSet.keepPackageName.contains(clazz)) { return clazz.type.getPackageDescriptor(); } else { return packagePrefix; @@ -86,38 +72,6 @@ public class ClassNameMinifier { return states.computeIfAbsent(packageName, NamingState::new); } - private void renameTypesInProtosOf(Iterable<DexMethod> methods) { - for (DexMethod method : methods) { - renameTypeWithoutClassDefinition(method.proto.returnType); - for (DexType type : method.proto.parameters.values) { - renameTypeWithoutClassDefinition(type); - } - } - } - - private void renameTypeWithoutClassDefinition(DexType type) { - if (type.isArrayType()) { - type = type.toBaseType(appInfo.dexItemFactory); - } - if (type.isClassType() && !renaming.containsKey(type)) { - DexClass clazz = appInfo.definitionFor(type); - if (clazz == null || !clazz.isLibraryClass()) { - if (!classIsBannedFromRenaming(type)) { - String packageName = packagePrefix == null ? type.getPackageDescriptor() : packagePrefix; - NamingState state = getStateFor(packageName); - renaming.put(type, state.nextTypeName()); - } - } - } - } - - private boolean classIsBannedFromRenaming(DexType type) { - String desc = type.toDescriptorString(); - int index = desc.indexOf('/'); - String prefix = desc.substring(0, index); - return index != -1 && BANNED_CLASS_PREFIXES.contains(prefix); - } - private void renameArrayTypeIfNeeded(DexType type) { if (type.isArrayType()) { DexType base = type.toBaseType(appInfo.dexItemFactory); diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java index 9a6300800..71a4dc634 100644 --- a/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java +++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfiguration.java @@ -24,6 +24,8 @@ public class ProguardConfiguration { private boolean ignoreWarnings = false; private boolean obfuscating = true; private boolean shrinking = true; + private boolean printUsage = false; + private Path printUsageFile; private boolean printMapping; private Path printMappingOutput; private boolean verbose = false; @@ -69,6 +71,14 @@ public class ProguardConfiguration { this.shrinking = shrinking; } + public void setPrintUsage(boolean printUsage) { + this.printUsage = printUsage; + } + + public void setPrintUsageFile(Path printUsageFile) { + this.printUsageFile = printUsageFile; + } + public void setPrintMapping(boolean printMapping) { this.printMapping = printMapping; } @@ -123,6 +133,8 @@ public class ProguardConfiguration { ignoreWarnings, obfuscating, shrinking, + printUsage, + printUsageFile, printMapping, printMappingOutput, verbose, @@ -145,6 +157,8 @@ public class ProguardConfiguration { private final boolean ignoreWarnings; private final boolean obfuscating; private final boolean shrinking; + private final boolean printUsage; + private final Path printUsageFile; private final boolean printMapping; private final Path printMappingOutput; private final boolean verbose; @@ -166,6 +180,8 @@ public class ProguardConfiguration { boolean ignoreWarnings, boolean obfuscating, boolean shrinking, + boolean printUsage, + Path printUsageFile, boolean printMapping, Path printMappingOutput, boolean verbose, @@ -185,6 +201,8 @@ public class ProguardConfiguration { this.ignoreWarnings = ignoreWarnings; this.obfuscating = obfuscating; this.shrinking = shrinking; + this.printUsage = printUsage; + this.printUsageFile = printUsageFile; this.printMapping = printMapping; this.printMappingOutput = printMappingOutput; this.verbose = verbose; @@ -249,6 +267,14 @@ public class ProguardConfiguration { return shrinking; } + public boolean isPrintUsage() { + return printUsage; + } + + public Path getPrintUsageFile() { + return printUsageFile; + } + public boolean isVerbose() { return verbose; } @@ -293,6 +319,8 @@ public class ProguardConfiguration { false /* ignoreWarnings */, false /* obfuscating */, false /* shrinking */, + false /* printUsage */, + null /* printUsageFile */, false /* printMapping */, null /* outputMapping */, false /* verbose */, diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java index 9fcb50a92..3b78e1b56 100644 --- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java +++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java @@ -55,8 +55,7 @@ public class ProguardConfigurationParser { "alwaysinline", "identifiernamestring", "whyarenotsimple"); private static final List<String> warnedSingleArgOptions = ImmutableList - .of("printusage", - "renamesourcefileattribute", + .of("renamesourcefileattribute", "dontnote", "printconfiguration", // TODO -outjars (http://b/37137994) and -adaptresourcefilecontents (http://b/37139570) @@ -154,6 +153,14 @@ public class ProguardConfigurationParser { configurationBuilder.setObfuscating(false); } else if (acceptString("dontshrink")) { configurationBuilder.setShrinking(false); + } else if (acceptString("printusage")) { + configurationBuilder.setPrintUsage(true); + skipWhitespace(); + if (isOptionalArgumentGiven()) { + configurationBuilder.setPrintUsageFile(parseFileName()); + } + // TODO(b/36799826): once fully implemented, no longer necessary to warn. + System.out.println("WARNING: Ignoring option: -printusage"); } else if (acceptString("verbose")) { configurationBuilder.setVerbose(true); } else if (acceptString("ignorewarnings")) { @@ -177,7 +184,7 @@ public class ProguardConfigurationParser { } else if (acceptString("printmapping")) { configurationBuilder.setPrintMapping(true); skipWhitespace(); - if (!eof() && peekChar() != '-') { + if (isOptionalArgumentGiven()) { configurationBuilder.setPrintMappingOutput(parseFileName()); } } else if (acceptString("assumenosideeffects")) { @@ -199,7 +206,7 @@ public class ProguardConfigurationParser { } else if (acceptString("printseeds")) { configurationBuilder.setPrintSeed(true); skipWhitespace(); - if (!eof() && peekChar() != '-') { + if (isOptionalArgumentGiven()) { configurationBuilder.setSeedFile(parseFileName()); } } else if (acceptString("obfuscationdictionary")) { @@ -271,7 +278,7 @@ public class ProguardConfigurationParser { Log.debug(ProguardConfigurationParser.class, "Skipping '-%s` option", name); } skipWhitespace(); - if (!eof() && peekChar() != '-') { + if (isOptionalArgumentGiven()) { skipSingleArgument(); } return true; @@ -794,6 +801,10 @@ public class ProguardConfigurationParser { return peekChar() == c; } + private boolean isOptionalArgumentGiven() { + return !eof() && !hasNextChar('-'); + } + private boolean acceptChar(char c) { if (hasNextChar(c)) { position++; @@ -938,7 +949,6 @@ public class ProguardConfigurationParser { } } - private void checkNotNegatedPattern() throws ProguardRuleParserException { skipWhitespace(); if (acceptChar('!')) { 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 04f67864d..3968c9ae0 100644 --- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java +++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java @@ -55,14 +55,15 @@ public class TreePruner { private List<DexProgramClass> getNewProgramClasses(List<DexProgramClass> classes) { List<DexProgramClass> newClasses = new ArrayList<>(); for (DexProgramClass clazz : classes) { - if (!appInfo.liveTypes.contains(clazz.type) && !options.debugKeepRules) { + if (!appInfo.liveTypes.contains(clazz.type)) { // The class is completely unused and we can remove it. if (Log.ENABLED) { Log.debug(getClass(), "Removing class: " + clazz); } } else { newClasses.add(clazz); - if (!appInfo.instantiatedTypes.contains(clazz.type) && !options.debugKeepRules) { + if (!appInfo.instantiatedTypes.contains(clazz.type) && + (!options.debugKeepRules || !hasDefaultConstructor(clazz))) { // The class is only needed as a type but never instantiated. Make it abstract to reflect // this. if (clazz.accessFlags.isFinal()) { @@ -86,6 +87,15 @@ public class TreePruner { return newClasses; } + private boolean hasDefaultConstructor(DexProgramClass clazz) { + for (DexEncodedMethod method : clazz.directMethods()) { + if (isDefaultConstructor(method)) { + return true; + } + } + return false; + } + private <S extends PresortedComparable<S>, T extends KeyedDexItem<S>> int firstUnreachableIndex( T[] items, Set<S> live) { for (int i = 0; i < items.length; i++) { @@ -96,6 +106,11 @@ public class TreePruner { return -1; } + private boolean isDefaultConstructor(DexEncodedMethod method) { + return method.accessFlags.isConstructor() && !method.accessFlags.isStatic() + && method.method.proto.parameters.isEmpty(); + } + private DexEncodedMethod[] reachableMethods(DexEncodedMethod[] methods, DexClass clazz) { int firstUnreachable = firstUnreachableIndex(methods, appInfo.liveMethods); // Return the original array if all methods are used. @@ -109,7 +124,7 @@ public class TreePruner { for (int i = firstUnreachable; i < methods.length; i++) { if (appInfo.liveMethods.contains(methods[i].getKey())) { reachableMethods.add(methods[i]); - } else if (options.debugKeepRules) { + } else if (options.debugKeepRules && isDefaultConstructor(methods[i])) { // Keep the method but rewrite its body, if it has one. reachableMethods.add(methods[i].accessFlags.isAbstract() ? methods[i] 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 01d8c2692..9d6cfa5ea 100644 --- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java +++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java @@ -59,6 +59,8 @@ public class InternalOptions { public OutputMode outputMode = OutputMode.Indexed; public boolean useTreeShaking = true; + public boolean printUsage = false; + public Path printUsageFile = null; public boolean printCfg = false; public String printCfgFile; |