diff options
author | android-build-team Robot <android-build-team-robot@google.com> | 2017-07-16 07:37:16 +0000 |
---|---|---|
committer | android-build-team Robot <android-build-team-robot@google.com> | 2017-07-16 07:37:16 +0000 |
commit | 5a59612a39e9a2b27cbacc2e4a252227be9aed35 (patch) | |
tree | 0e46f083cf6dfa76bad446e38675aec3a968a706 | |
parent | e9e6d3d3613a0454638d0097ec9ced3ca400c6ac (diff) | |
parent | 4b9460ad97b53249b353cebe58b59117822d07b2 (diff) | |
download | r8-5a59612a39e9a2b27cbacc2e4a252227be9aed35.tar.gz |
release-request-05263112-375a-4b1f-a657-a14bb2a5c5a3-for-git_oc-mr1-release-4185249 snap-temp-L63000000082739046
Change-Id: Ie4ab9077b5e69284fee1abc96d1aea9140f0bcfd
55 files changed, 824 insertions, 507 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/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java index 0e89d4a10..f336a3d2d 100644 --- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java +++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java @@ -67,7 +67,7 @@ public class VirtualFile { // TODO(sgjesse): Does "minimal main dex" combined with "leave space for growth" make sense? } - private static final int MAX_ENTRIES = (Short.MAX_VALUE << 1) + 1; + private static final int MAX_ENTRIES = Constants.U16BIT_MAX + 1; /** * When distributing classes across files we aim to leave some space. The amount of space left is * driven by this constant. 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/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java index 3bcf6e749..023cfb0e4 100644 --- a/src/main/java/com/android/tools/r8/graph/DexClass.java +++ b/src/main/java/com/android/tools/r8/graph/DexClass.java @@ -7,8 +7,11 @@ import com.android.tools.r8.Resource; import com.android.tools.r8.dex.MixedSectionCollection; import com.android.tools.r8.errors.CompilationError; import com.android.tools.r8.errors.Unreachable; + import com.google.common.base.MoreObjects; +import java.util.function.Consumer; + public abstract class DexClass extends DexItem { private static final DexEncodedMethod[] NO_METHODS = {}; @@ -71,6 +74,14 @@ public abstract class DexClass extends DexItem { return MoreObjects.firstNonNull(virtualMethods, NO_METHODS); } + public void forEachMethod(Consumer<DexEncodedMethod> consumer) { + for (DexEncodedMethod method : directMethods()) { + consumer.accept(method); + } + for (DexEncodedMethod method : virtualMethods()) { + consumer.accept(method); + } + } public DexEncodedField[] staticFields() { return MoreObjects.firstNonNull(staticFields, NO_FIELDS); 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/graph/ObjectToOffsetMapping.java b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java index 7dab70aff..74a08003e 100644 --- a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java +++ b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java @@ -88,7 +88,7 @@ public class ObjectToOffsetMapping { private void setIndexes(IndexedDexItem[] items) { int index = 0; for (IndexedDexItem item : items) { - item.assignVirtualFileIndex(virtualFileId, index++); + item.assignVirtualFileIndex(virtualFileId, index); // For strings collect the first jumbo string (if any). if (index > Constants.MAX_NON_JUMBO_INDEX) { assert item instanceof DexString; @@ -96,6 +96,7 @@ public class ObjectToOffsetMapping { firstJumboString = (DexString) item; } } + index++; } } diff --git a/src/main/java/com/android/tools/r8/ir/code/Value.java b/src/main/java/com/android/tools/r8/ir/code/Value.java index 92bb7b20a..e0bfdd0c9 100644 --- a/src/main/java/com/android/tools/r8/ir/code/Value.java +++ b/src/main/java/com/android/tools/r8/ir/code/Value.java @@ -57,7 +57,7 @@ public class Value { public static final Value UNDEFINED = new Value(-1, MoveType.OBJECT, null); protected final int number; - protected MoveType type; + protected final MoveType type; public Instruction definition = null; private LinkedList<Instruction> users = new LinkedList<>(); private Set<Instruction> uniqueUsers = null; @@ -71,7 +71,7 @@ public class Value { private boolean isThis = false; private boolean isArgument = false; private LongInterval valueRange; - private DebugData debugData; + private final DebugData debugData; public Value(int number, MoveType type, DebugInfo debugInfo) { this.number = number; diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java index c5068678f..4d8eee148 100644 --- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java +++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraph.java @@ -20,6 +20,7 @@ import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness; import com.google.common.collect.Sets; import java.util.ArrayList; import java.util.Collections; +import java.util.HashMap; import java.util.IdentityHashMap; import java.util.LinkedHashMap; import java.util.LinkedHashSet; @@ -48,13 +49,13 @@ public class CallGraph { public final DexEncodedMethod method; private int invokeCount = 0; - private boolean isRecursive = false; + private boolean isSelfRecursive = false; // Outgoing calls from this method. - public final Set<Node> calls = new LinkedHashSet<>(); + public final Set<Node> callees = new LinkedHashSet<>(); // Incoming calls to this method. - public final Set<Node> callees = new LinkedHashSet<>(); + public final Set<Node> callers = new LinkedHashSet<>(); private Node(DexEncodedMethod method) { this.method = method; @@ -64,24 +65,24 @@ public class CallGraph { return method.accessFlags.isBridge(); } - private void addCalls(Node method) { - calls.add(method); + private void addCallee(Node method) { + callees.add(method); } private void addCaller(Node method) { - callees.add(method); + callers.add(method); } - boolean isRecursive() { - return isRecursive; + boolean isSelfRecursive() { + return isSelfRecursive; } boolean isLeaf() { - return calls.isEmpty(); + return callees.isEmpty(); } int callDegree() { - return calls.size(); + return callees.size(); } @Override @@ -100,31 +101,31 @@ public class CallGraph { builder.append("MethodNode for: "); builder.append(method.qualifiedName()); builder.append(" ("); - builder.append(calls.size()); - builder.append(" calls, "); builder.append(callees.size()); - builder.append(" callees"); + builder.append(" callees, "); + builder.append(callers.size()); + builder.append(" callers"); if (isBridge()) { builder.append(", bridge"); } - if (isRecursive()) { + if (isSelfRecursive()) { builder.append(", recursive"); } builder.append(", invoke count " + invokeCount); builder.append(").\n"); - if (calls.size() > 0) { - builder.append("Calls:\n"); - for (Node call : calls) { + if (callees.size() > 0) { + builder.append("Callees:\n"); + for (Node call : callees) { builder.append(" "); builder.append(call.method.qualifiedName()); builder.append("\n"); } } - if (callees.size() > 0) { - builder.append("Callees:\n"); - for (Node callee : callees) { + if (callers.size() > 0) { + builder.append("Callers:\n"); + for (Node caller : callers) { builder.append(" "); - builder.append(callee.method.qualifiedName()); + builder.append(caller.method.qualifiedName()); builder.append("\n"); } } @@ -154,7 +155,7 @@ public class CallGraph { return leaves; } - public boolean brokeCycles() { + public boolean hasBrokeCycles() { return brokeCycles; } @@ -182,6 +183,8 @@ public class CallGraph { } private final Map<DexEncodedMethod, Node> nodes = new LinkedHashMap<>(); + private final Map<DexEncodedMethod, Set<DexEncodedMethod>> breakers = new HashMap<>(); + private List<Node> leaves = null; private Set<DexEncodedMethod> singleCallSite = Sets.newIdentityHashSet(); private Set<DexEncodedMethod> doubleCallSite = Sets.newIdentityHashSet(); @@ -190,22 +193,15 @@ public class CallGraph { GraphLense graphLense) { CallGraph graph = new CallGraph(); - for (DexClass clazz : application.classes()) { - for (DexEncodedMethod method : clazz.directMethods()) { - Node node = graph.ensureMethodNode(method); - InvokeExtractor extractor = new InvokeExtractor(appInfo, graphLense, node, graph); - method.registerReachableDefinitions(extractor); - } - for (DexEncodedMethod method : clazz.virtualMethods()) { + clazz.forEachMethod( method -> { Node node = graph.ensureMethodNode(method); InvokeExtractor extractor = new InvokeExtractor(appInfo, graphLense, node, graph); method.registerReachableDefinitions(extractor); - } + }); } assert allMethodsExists(application, graph); - graph.fillCallSiteSets(appInfo); graph.fillInitialLeaves(); return graph; @@ -255,12 +251,7 @@ public class CallGraph { private static boolean allMethodsExists(DexApplication application, CallGraph graph) { for (DexProgramClass clazz : application.classes()) { - for (DexEncodedMethod method : clazz.directMethods()) { - assert graph.nodes.get(method) != null; - } - for (DexEncodedMethod method : clazz.virtualMethods()) { - assert graph.nodes.get(method) != null; - } + clazz.forEachMethod( method -> { assert graph.nodes.get(method) != null; }); } return true; } @@ -275,7 +266,7 @@ public class CallGraph { List<DexEncodedMethod> result = new ArrayList<>(); List<Node> newLeaves = new ArrayList<>(); for (Node leaf : leaves) { - assert nodes.containsKey(leaf.method) && nodes.get(leaf.method).calls.isEmpty(); + assert nodes.containsKey(leaf.method) && nodes.get(leaf.method).callees.isEmpty(); remove(leaf, newLeaves); result.add(leaf.method); } @@ -368,30 +359,30 @@ public class CallGraph { assert caller != null; assert callee != null; if (caller != callee) { - caller.addCalls(callee); + caller.addCallee(callee); callee.addCaller(caller); } else { - caller.isRecursive = true; + caller.isSelfRecursive = true; } callee.invokeCount++; } private Set<DexEncodedMethod> removeAllCalls(Node node) { Set<DexEncodedMethod> calls = Sets.newIdentityHashSet(); - for (Node call : node.calls) { + for (Node call : node.callees) { calls.add(call.method); - call.callees.remove(node); + call.callers.remove(node); } - node.calls.clear(); + node.callees.clear(); return calls; } private void remove(Node node, List<Node> leaves) { assert node != null; - for (Node callee : node.callees) { - boolean removed = callee.calls.remove(node); - if (callee.isLeaf()) { - leaves.add(callee); + for (Node caller : node.callers) { + boolean removed = caller.callees.remove(node); + if (caller.isLeaf()) { + leaves.add(caller); } assert removed; } 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 1586496c1..98a261914 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 @@ -40,7 +40,6 @@ import com.android.tools.r8.utils.Timing; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutionException; @@ -277,11 +276,9 @@ public class IRConverter { // Process the application identifying outlining candidates. timing.begin("IR conversion phase 1"); - int count = 0; OptimizationFeedback directFeedback = new OptimizationFeedbackDirect(); OptimizationFeedbackDelayed delayedFeedback = new OptimizationFeedbackDelayed(); while (!callGraph.isEmpty()) { - count++; CallGraph.Leaves leaves = callGraph.pickLeaves(); List<DexEncodedMethod> methods = leaves.getLeaves(); assert methods.size() > 0; @@ -297,15 +294,26 @@ public class IRConverter { // optimization feedback to reprocess methods affected by it. This is required to get // deterministic behaviour, as the processing order within each set of leaves is // non-deterministic. - for (DexEncodedMethod method : methods) { - futures.add(executorService.submit(() -> { + + // Due to a race condition, we serialize processing of methods if cycles are broken. + // TODO(bak) + if (leaves.hasBrokeCycles()) { + for (DexEncodedMethod method : methods) { processMethod(method, - leaves.brokeCycles() ? delayedFeedback : directFeedback, + leaves.hasBrokeCycles() ? delayedFeedback : directFeedback, outliner == null ? Outliner::noProcessing : outliner::identifyCandidates); - })); + } + } else { + for (DexEncodedMethod method : methods) { + futures.add(executorService.submit(() -> { + processMethod(method, + leaves.hasBrokeCycles() ? delayedFeedback : directFeedback, + outliner == null ? Outliner::noProcessing : outliner::identifyCandidates); + })); + } + ThreadUtils.awaitFutures(futures); } - ThreadUtils.awaitFutures(futures); - if (leaves.brokeCycles()) { + if (leaves.hasBrokeCycles()) { // If cycles in the call graph were broken, then re-process all methods which are // affected by the optimization feedback of other methods in this group. methods = delayedFeedback.applyAndClear(methods, leaves); @@ -320,13 +328,9 @@ public class IRConverter { Builder builder = new Builder(application); builder.setHighestSortingString(highestSortingString); - // Second inlining pass. - if ((inliner != null) && (inliner.doubleInlineCallers.size() > 0)) { - inliner.applyDoubleInlining = true; - for (DexEncodedMethod method : inliner.doubleInlineCallers) { - processMethod(method, ignoreOptimizationFeedback, Outliner::noProcessing); - assert method.isProcessed(); - } + // Second inlining pass for dealing with double inline callers. + if (inliner != null) { + inliner.processDoubleInlineCallers(this, ignoreOptimizationFeedback); } synthesizeLambdaClasses(builder); @@ -363,8 +367,7 @@ public class IRConverter { } private void clearDexMethodCompilationState(DexProgramClass clazz) { - Arrays.stream(clazz.directMethods()).forEach(DexEncodedMethod::markNotProcessed); - Arrays.stream(clazz.virtualMethods()).forEach(DexEncodedMethod::markNotProcessed); + clazz.forEachMethod(DexEncodedMethod::markNotProcessed); } /** @@ -413,12 +416,7 @@ public class IRConverter { public void optimizeSynthesizedClass(DexProgramClass clazz) { // Process the generated class, but don't apply any outlining. - for (DexEncodedMethod method : clazz.directMethods()) { - optimizeSynthesizedMethod(method); - } - for (DexEncodedMethod method : clazz.virtualMethods()) { - optimizeSynthesizedMethod(method); - } + clazz.forEachMethod(this::optimizeSynthesizedMethod); } public void optimizeSynthesizedMethod(DexEncodedMethod method) { @@ -430,7 +428,7 @@ public class IRConverter { return options.useSmaliSyntax ? method.toSmaliString(null) : method.codeToString(); } - private void processMethod(DexEncodedMethod method, + public void processMethod(DexEncodedMethod method, OptimizationFeedback feedback, BiConsumer<IRCode, DexEncodedMethod> outlineHandler) { Code code = method.getCode(); 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/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java index 2364668ab..203ca80a3 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java @@ -66,6 +66,7 @@ import java.util.ArrayList; import java.util.Comparator; import java.util.HashMap; import java.util.HashSet; +import java.util.IdentityHashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -853,7 +854,7 @@ public class CodeRewriter { private void splitPhiConstants(IRCode code, BasicBlock block) { for (int i = 0; i < block.getPredecessors().size(); i++) { - Map<ConstNumber, ConstNumber> oldToNew = new HashMap<>(); + Map<ConstNumber, ConstNumber> oldToNew = new IdentityHashMap<>(); BasicBlock predecessor = block.getPredecessors().get(i); for (Phi phi : block.getPhis()) { Value operand = phi.getOperand(i); diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java index 1f21f5245..6d6981757 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java @@ -19,7 +19,9 @@ import com.android.tools.r8.ir.code.InvokeMethod; import com.android.tools.r8.ir.code.Value; import com.android.tools.r8.ir.code.ValueNumberGenerator; import com.android.tools.r8.ir.conversion.CallGraph; +import com.android.tools.r8.ir.conversion.IRConverter; import com.android.tools.r8.ir.conversion.LensCodeRewriter; +import com.android.tools.r8.ir.conversion.OptimizationFeedback; import com.android.tools.r8.logging.Log; import com.android.tools.r8.utils.InternalOptions; import com.google.common.collect.Sets; @@ -39,10 +41,10 @@ public class Inliner { private final InternalOptions options; // State for inlining methods which are known to be called twice. - public boolean applyDoubleInlining = false; - public final Set<DexEncodedMethod> doubleInlineCallers = Sets.newIdentityHashSet(); - public final Set<DexEncodedMethod> doubleInlineSelectedTargets = Sets.newIdentityHashSet(); - public final Map<DexEncodedMethod, DexEncodedMethod> doubleInlineeCandidates = new HashMap<>(); + private boolean applyDoubleInlining = false; + private final Set<DexEncodedMethod> doubleInlineCallers = Sets.newIdentityHashSet(); + private final Set<DexEncodedMethod> doubleInlineSelectedTargets = Sets.newIdentityHashSet(); + private final Map<DexEncodedMethod, DexEncodedMethod> doubleInlineeCandidates = new HashMap<>(); public Inliner(AppInfoWithSubtyping appInfo, GraphLense graphLense, InternalOptions options) { this.appInfo = appInfo; @@ -89,7 +91,7 @@ public class Inliner { return result; } - protected boolean hasInliningAccess(DexEncodedMethod method, DexEncodedMethod target) { + boolean hasInliningAccess(DexEncodedMethod method, DexEncodedMethod target) { if (target.accessFlags.isPublic()) { return true; } @@ -105,6 +107,40 @@ public class Inliner { return methodHolder.isSamePackage(targetHolder); } + synchronized DexEncodedMethod doubleInlining(DexEncodedMethod method, + DexEncodedMethod target) { + if (!applyDoubleInlining) { + if (doubleInlineeCandidates.containsKey(target)) { + // Both calls can be inlined. + doubleInlineCallers.add(doubleInlineeCandidates.get(target)); + doubleInlineCallers.add(method); + doubleInlineSelectedTargets.add(target); + } else { + // First call can be inlined. + doubleInlineeCandidates.put(target, method); + } + // Just preparing for double inlining. + return null; + } else { + // Don't perform the actual inlining if this was not selected. + if (!doubleInlineSelectedTargets.contains(target)) { + return null; + } + } + return target; + } + + public synchronized void processDoubleInlineCallers(IRConverter converter, + OptimizationFeedback feedback) { + if (doubleInlineCallers.size() > 0) { + applyDoubleInlining = true; + for (DexEncodedMethod method : doubleInlineCallers) { + converter.processMethod(method, feedback, Outliner::noProcessing); + assert method.isProcessed(); + } + } + } + public enum Constraint { // The ordinal values are important so please do not reorder. NEVER, // Never inline this. diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java index febef8206..4b93d8d77 100644 --- a/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java +++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningOracle.java @@ -82,28 +82,6 @@ public class InliningOracle { return candidate; } - private synchronized DexEncodedMethod doubleInlining(DexEncodedMethod candidate) { - if (!inliner.applyDoubleInlining) { - if (inliner.doubleInlineeCandidates.containsKey(candidate)) { - // Both calls can be inlined. - inliner.doubleInlineCallers.add(inliner.doubleInlineeCandidates.get(candidate)); - inliner.doubleInlineCallers.add(method); - inliner.doubleInlineSelectedTargets.add(candidate); - } else { - // First call can be inlined. - inliner.doubleInlineeCandidates.put(candidate, method); - } - // Just preparing for double inlining. - return null; - } else { - // Don't perform the actual inlining if this was not selected. - if (!inliner.doubleInlineSelectedTargets.contains(candidate)) { - return null; - } - } - return candidate; - } - private Reason computeInliningReason(DexEncodedMethod target) { if (target.getOptimizationInfo().forceInline()) { return Reason.FORCE; @@ -185,7 +163,7 @@ public class InliningOracle { } // Attempt to inline a candidate that is only called twice. - if ((reason == Reason.DUAL_CALLER) && (doubleInlining(target) == null)) { + if ((reason == Reason.DUAL_CALLER) && (inliner.doubleInlining(method, target) == null)) { if (info != null) { info.exclude(invoke, "target is not ready for double inlining"); } @@ -253,7 +231,7 @@ public class InliningOracle { } // Attempt to inline a candidate that is only called twice. - if ((reason == Reason.DUAL_CALLER) && (doubleInlining(candidate) == null)) { + if ((reason == Reason.DUAL_CALLER) && (inliner.doubleInlining(method, candidate) == null)) { if (info != null) { info.exclude(invoke, "target is not ready for double inlining"); } diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java index 13f2d2953..fe59b791b 100644 --- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java +++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java @@ -38,6 +38,8 @@ import it.unimi.dsi.fastutil.ints.IntArraySet; import it.unimi.dsi.fastutil.ints.IntIterator; import it.unimi.dsi.fastutil.ints.IntSet; import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; @@ -136,7 +138,7 @@ public class LinearScanRegisterAllocator implements RegisterAllocator { private List<LiveIntervals> inactive = new LinkedList<>(); // List of intervals that no register has been allocated to sorted by first live range. private PriorityQueue<LiveIntervals> unhandled = - new PriorityQueue<>((o1, o2) -> Integer.compare(o1.getStart(), o2.getStart())); + new PriorityQueue<>(Comparator.comparingInt(LiveIntervals::getStart)); // The first register used for parallel moves. After register allocation the parallel move // temporary registers are [firstParallelMoveTemporary, maxRegisterNumber]. @@ -1354,10 +1356,6 @@ public class LinearScanRegisterAllocator implements RegisterAllocator { unhandled.add(split); } else if (blockedPosition > unhandledInterval.getEnd()) { // Spilling can make a register available for the entire interval. - // It would have been nice to use assignRegisterToUnhandledInterval here, but unfortunately - // the order of the operations are extremely important here. updateRegisterState has to - // happen before spillOverlappingActiveIntervals and takeRegistersForIntervals has to happen - // after. assignRegisterAndSpill(unhandledInterval, needsRegisterPair, candidate); } else { // Spilling only makes a register available for the first part of current. @@ -1390,7 +1388,9 @@ public class LinearScanRegisterAllocator implements RegisterAllocator { } private void assignRegisterAndSpill( - LiveIntervals unhandledInterval, boolean needsRegisterPair, int candidate) { + LiveIntervals unhandledInterval, + boolean needsRegisterPair, + int candidate) { assignRegister(unhandledInterval, candidate); updateRegisterState(candidate, needsRegisterPair); // Split and spill intersecting active intervals for this register. @@ -1402,14 +1402,21 @@ public class LinearScanRegisterAllocator implements RegisterAllocator { splitOverlappingInactiveIntervals(unhandledInterval, needsRegisterPair, candidate); } - private void splitOverlappingInactiveIntervals(LiveIntervals unhandledInterval, - boolean needsRegisterPair, int candidate) { + private void splitOverlappingInactiveIntervals( + LiveIntervals unhandledInterval, + boolean needsRegisterPair, + int candidate) { Iterator<LiveIntervals> inactiveIterator = inactive.iterator(); while (inactiveIterator.hasNext()) { LiveIntervals intervals = inactiveIterator.next(); if ((intervals.usesRegister(candidate) || (needsRegisterPair && intervals.usesRegister(candidate + 1))) && intervals.overlaps(unhandledInterval)) { + // If these assertions trigger we have changed the way blocked parts of intervals + // are handled. If we ever get intervals with fixed registers in here, we need + // to split them before the first use in the same way that we do when spilling + // overlapping active intervals. + assert !intervals.isLinked() || intervals.isArgumentInterval(); if (intervals.getStart() > unhandledInterval.getStart()) { // The inactive live intervals hasn't started yet. Clear the temporary register // assignment and move back to unhandled for register reassignment. @@ -1426,8 +1433,10 @@ public class LinearScanRegisterAllocator implements RegisterAllocator { } } - private void spillOverlappingActiveIntervals(LiveIntervals unhandledInterval, - boolean needsRegisterPair, int candidate) { + private void spillOverlappingActiveIntervals( + LiveIntervals unhandledInterval, + boolean needsRegisterPair, + int candidate) { List<LiveIntervals> newActive = new ArrayList<>(); Iterator<LiveIntervals> activeIterator = active.iterator(); while (activeIterator.hasNext()) { @@ -1844,8 +1853,6 @@ public class LinearScanRegisterAllocator implements RegisterAllocator { live.add(use); addLiveRange(use, block, number); } - LiveIntervals useIntervals = use.getLiveIntervals(); - useIntervals.addUse(new LiveIntervalsUse(number, Constants.U16BIT_MAX, true)); } Value use = instruction.getPreviousLocalValue(); if (use != null) { @@ -1854,8 +1861,6 @@ public class LinearScanRegisterAllocator implements RegisterAllocator { live.add(use); addLiveRange(use, block, number); } - LiveIntervals useIntervals = use.getLiveIntervals(); - useIntervals.addUse(new LiveIntervalsUse(number, Constants.U16BIT_MAX, true)); } } } @@ -1887,14 +1892,27 @@ public class LinearScanRegisterAllocator implements RegisterAllocator { Value previous = null; for (int i = 0; i < arguments.size(); i++) { Value argument = arguments.get(i); - // TODO(ager): Conditionally create a new argument if it is not already a move. - // Reverted optimization from CL: https://r8-review.googlesource.com/c/1985/ - // Not considering debug-uses causes a unlinked/non-consecutive register in some cases. - Value newArgument = createValue(argument.outType()); - Move move = new Move(newArgument, argument); - move.setBlock(invoke.getBlock()); - replaceArgument(invoke, i, newArgument); - insertAt.add(move); + Value newArgument = argument; + // In debug mode, we have debug instructions that are also moves. Do not generate another + // move if there already is a move instruction that we can use. We generate moves if: + // + // 1. the argument is not defined by a move, + // + // 2. the argument is already linked or would cause a cycle if linked, or + // + // 3. the argument has a register constraint (the argument moves are there to make the + // input value to a ranged invoke unconstrained.) + if (argument.definition == null || + !argument.definition.isMove() || + argument.isLinked() || + argument == previous || + argument.hasRegisterConstraint()) { + newArgument = createValue(argument.outType()); + Move move = new Move(newArgument, argument); + move.setBlock(invoke.getBlock()); + replaceArgument(invoke, i, newArgument); + insertAt.add(move); + } if (previous != null) { previous.linkTo(newArgument); } diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java index 9c28724a7..06b33f473 100644 --- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java +++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervals.java @@ -319,7 +319,7 @@ public class LiveIntervals { public int firstUseAfter(int unhandledStart) { for (LiveIntervalsUse use : uses) { - if (use.getPosition() >= unhandledStart && !use.isDebugUse()) { + if (use.getPosition() >= unhandledStart) { return use.getPosition(); } } diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervalsUse.java b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervalsUse.java index edf876ded..db8e48de6 100644 --- a/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervalsUse.java +++ b/src/main/java/com/android/tools/r8/ir/regalloc/LiveIntervalsUse.java @@ -8,16 +8,10 @@ import static com.android.tools.r8.dex.Constants.U16BIT_MAX; public class LiveIntervalsUse implements Comparable<LiveIntervalsUse> { private final int position; private final int limit; - private final boolean debugUse; public LiveIntervalsUse(int position, int limit) { - this(position, limit, false); - } - - public LiveIntervalsUse(int position, int limit, boolean debugUse) { this.position = position; this.limit = limit; - this.debugUse = debugUse; } public int getPosition() { @@ -53,8 +47,4 @@ public class LiveIntervalsUse implements Comparable<LiveIntervalsUse> { public boolean hasConstraint() { return limit < U16BIT_MAX; } - - public boolean isDebugUse() { - return debugUse; - } } 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/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java index 7b9d45d45..e5088347f 100644 --- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java +++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java @@ -278,8 +278,11 @@ public class AndroidApp { try (Closer closer = Closer.create()) { List<Resource> dexProgramSources = getDexProgramResources(); for (int i = 0; i < dexProgramSources.size(); i++) { - Path fileName = directory.resolve(outputMode.getFileName(dexProgramSources.get(i), i)); - Files.copy(dexProgramSources.get(i).getStream(closer), fileName, options); + Path filePath = directory.resolve(outputMode.getOutputPath(dexProgramSources.get(i), i)); + if (!Files.exists(filePath.getParent())) { + Files.createDirectories(filePath.getParent()); + } + Files.copy(dexProgramSources.get(i).getStream(closer), filePath, options); } } } @@ -333,7 +336,7 @@ public class AndroidApp { try (ZipOutputStream out = new ZipOutputStream(Files.newOutputStream(archive, options))) { List<Resource> dexProgramSources = getDexProgramResources(); for (int i = 0; i < dexProgramSources.size(); i++) { - ZipEntry zipEntry = new ZipEntry(outputMode.getFileName(dexProgramSources.get(i), i)); + ZipEntry zipEntry = new ZipEntry(outputMode.getOutputPath(dexProgramSources.get(i), i)); byte[] bytes = ByteStreams.toByteArray(dexProgramSources.get(i).getStream(closer)); zipEntry.setSize(bytes.length); out.putNextEntry(zipEntry); diff --git a/src/main/java/com/android/tools/r8/utils/FileUtils.java b/src/main/java/com/android/tools/r8/utils/FileUtils.java index 47a72a38a..16f41cc04 100644 --- a/src/main/java/com/android/tools/r8/utils/FileUtils.java +++ b/src/main/java/com/android/tools/r8/utils/FileUtils.java @@ -75,9 +75,12 @@ public class FileUtils { public static Path validateOutputFile(Path path) throws CompilationException { if (path != null) { - if (!isZipFile(path) && !(Files.exists(path) && Files.isDirectory(path))) { + boolean isJarOrZip = isZipFile(path) || isJarFile(path); + if (!isJarOrZip && !(Files.exists(path) && Files.isDirectory(path))) { throw new CompilationException( - "Invalid output: " + path + "\nOutput must be a zip archive or an existing directory"); + "Invalid output: " + + path + + "\nOutput must be a .zip or .jar archive or an existing directory"); } } return path; 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; diff --git a/src/main/java/com/android/tools/r8/utils/OutputMode.java b/src/main/java/com/android/tools/r8/utils/OutputMode.java index ce743e82e..1bdf50174 100644 --- a/src/main/java/com/android/tools/r8/utils/OutputMode.java +++ b/src/main/java/com/android/tools/r8/utils/OutputMode.java @@ -10,21 +10,21 @@ import java.util.Set; public enum OutputMode { Indexed { @Override - String getFileName(Resource resource, int index) { + String getOutputPath(Resource resource, int index) { return index == 0 ? "classes.dex" : ("classes" + (index + 1) + ".dex"); } }, FilePerClass { @Override - String getFileName(Resource resource, int index) { + String getOutputPath(Resource resource, int index) { Set<String> classDescriptors = resource.getClassDescriptors(); assert classDescriptors != null; assert classDescriptors.size() == 1; String classDescriptor = classDescriptors.iterator().next(); - assert !classDescriptor.contains("."); - return DescriptorUtils.descriptorToJavaType(classDescriptor) + ".dex"; + assert DescriptorUtils.isClassDescriptor(classDescriptor); + return classDescriptor.substring(1, classDescriptor.length() - 1) + ".dex"; } }; - abstract String getFileName(Resource resource, int index); + abstract String getOutputPath(Resource resource, int index); } diff --git a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java index db81f17a1..d8b9bbc07 100644 --- a/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java +++ b/src/test/java/com/android/tools/r8/D8IncrementalRunExamplesAndroidOTest.java @@ -5,6 +5,7 @@ package com.android.tools.r8; import static com.android.tools.r8.utils.FileUtils.JAR_EXTENSION; +import static org.junit.Assert.assertEquals; import com.android.tools.r8.errors.CompilationError; import com.android.tools.r8.errors.InternalCompilerError; @@ -264,18 +265,25 @@ public abstract class D8IncrementalRunExamplesAndroidOTest D8IncrementalTestRunner test = test(testName, testPackage, mainClass); test.compileClassesTogether(inputJarFile, out); - String[] dexFiles = out.toFile().list(); + + String[] topLevelDir = out.toFile().list(); + assert topLevelDir != null; + assertEquals(1, topLevelDir.length); + assertEquals("incremental", topLevelDir[0]); + + String[] dexFiles = out.resolve(topLevelDir[0]).toFile().list(); assert dexFiles != null; Arrays.sort(dexFiles); String[] expectedFileNames = { - "incremental.IncrementallyCompiled$A$AB.dex", - "incremental.IncrementallyCompiled$A.dex", - "incremental.IncrementallyCompiled$B$BA.dex", - "incremental.IncrementallyCompiled$B.dex", - "incremental.IncrementallyCompiled$C.dex", - "incremental.IncrementallyCompiled.dex" + "IncrementallyCompiled$A$AB.dex", + "IncrementallyCompiled$A.dex", + "IncrementallyCompiled$B$BA.dex", + "IncrementallyCompiled$B.dex", + "IncrementallyCompiled$C.dex", + "IncrementallyCompiled.dex" }; + Arrays.sort(expectedFileNames); Assert.assertArrayEquals(expectedFileNames, dexFiles); } diff --git a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java index 8dc725508..eba8db600 100644 --- a/src/test/java/com/android/tools/r8/JctfTestSpecifications.java +++ b/src/test/java/com/android/tools/r8/JctfTestSpecifications.java @@ -138,7 +138,7 @@ public class JctfTestSpecifications { // 1) t01 // org.junit.ComparisonFailure: expected:<get[]StackTrace> but was:<get[Thread]StackTrace> - .put("lang.Thread.enumerate$Ljava_lang_Thread.Thread_enumerate_A02", any()) + .put("lang.Thread.enumerate_Ljava_lang_Thread.Thread_enumerate_A02", any()) // 1) t01 // java.lang.AssertionError: test failed with error:java.lang.SecurityException @@ -153,7 +153,7 @@ public class JctfTestSpecifications { // java.lang.AssertionError: Expected exception: java.lang.IllegalThreadStateException .put("lang.Thread.getAllStackTraces.Thread_getAllStackTraces_A01", - match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0))) + match(runtimes(DexVm.ART_7_0_0))) // 1) t01 // java.lang.AssertionError @@ -195,7 +195,7 @@ public class JctfTestSpecifications { // java.lang.UnsupportedOperationException .put("lang.Thread.getContextClassLoader.Thread_getContextClassLoader_A03", - match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0))) + match(runtimes(DexVm.ART_7_0_0))) // 1) t01 // java.lang.AssertionError: improper ClassLoader expected same:<null> was not:<dalvik.system.PathClassLoader[DexPathList[[dex file "/tmp/junit7794202178392390143/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]]]> @@ -316,8 +316,8 @@ public class JctfTestSpecifications { // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredConstructors.Class_getDeclaredConstructors_A02" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 3) t03 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> - // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredConstructor$Ljava_lang_Class/Class_getDeclaredConstructor_A03; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredConstructor$Ljava_lang_Class.Class_getDeclaredConstructor_A03" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredConstructor_Ljava_lang_Class/Class_getDeclaredConstructor_A03; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredConstructor_Ljava_lang_Class.Class_getDeclaredConstructor_A03" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 4) t04 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredFields/Class_getDeclaredFields_A02; @@ -332,8 +332,8 @@ public class JctfTestSpecifications { // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredMethods.Class_getDeclaredMethods_A02" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 7) t07 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> - // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredMethodLjava_lang_String$Ljava_lang_Class/Class_getDeclaredMethod_A05; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredMethodLjava_lang_String$Ljava_lang_Class.Class_getDeclaredMethod_A05" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredMethodLjava_lang_String_Ljava_lang_Class/Class_getDeclaredMethod_A05; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredMethodLjava_lang_String_Ljava_lang_Class.Class_getDeclaredMethod_A05" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 8) t08 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredClasses/Class_getDeclaredClasses_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredClasses.Class_getDeclaredClasses_A02" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -341,8 +341,8 @@ public class JctfTestSpecifications { // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredConstructors/Class_getDeclaredConstructors_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredConstructors.Class_getDeclaredConstructors_A02" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 10) t10 - // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredConstructor$Ljava_lang_Class/Class_getDeclaredConstructor_A03; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredConstructor$Ljava_lang_Class.Class_getDeclaredConstructor_A03" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredConstructor_Ljava_lang_Class/Class_getDeclaredConstructor_A03; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredConstructor_Ljava_lang_Class.Class_getDeclaredConstructor_A03" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 11) t11 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredFields/Class_getDeclaredFields_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredFields.Class_getDeclaredFields_A02" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -353,8 +353,8 @@ public class JctfTestSpecifications { // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredMethods/Class_getDeclaredMethods_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredMethods.Class_getDeclaredMethods_A02" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 14) t14 - // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredMethodLjava_lang_String$Ljava_lang_Class/Class_getDeclaredMethod_A05; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredMethodLjava_lang_String$Ljava_lang_Class.Class_getDeclaredMethod_A05" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredMethodLjava_lang_String_Ljava_lang_Class/Class_getDeclaredMethod_A05; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredMethodLjava_lang_String_Ljava_lang_Class.Class_getDeclaredMethod_A05" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 15) t15 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/newInstance/Class_newInstance_A07; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.newInstance.Class_newInstance_A07" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -372,8 +372,8 @@ public class JctfTestSpecifications { // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getConstructors.Class_getConstructors_A02" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 19) t19 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> - // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getConstructor$Ljava_lang_Class/Class_getConstructor_A04; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getConstructor$Ljava_lang_Class.Class_getConstructor_A04" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getConstructor_Ljava_lang_Class/Class_getConstructor_A04; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getConstructor_Ljava_lang_Class.Class_getConstructor_A04" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 20) t20 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getFields/Class_getFields_A02; @@ -388,8 +388,8 @@ public class JctfTestSpecifications { // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getMethods.Class_getMethods_A02" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 23) t23 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> - // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getMethodLjava_lang_String$Ljava_lang_Class/Class_getMethod_A05; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String$Ljava_lang_Class.Class_getMethod_A05" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getMethodLjava_lang_String_Ljava_lang_Class/Class_getMethod_A05; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A05" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 24) t24 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getClasses/Class_getClasses_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getClasses.Class_getClasses_A02" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -397,8 +397,8 @@ public class JctfTestSpecifications { // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getConstructors/Class_getConstructors_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getConstructors.Class_getConstructors_A02" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 26) t26 - // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getConstructor$Ljava_lang_Class/Class_getConstructor_A04; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getConstructor$Ljava_lang_Class.Class_getConstructor_A04" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getConstructor_Ljava_lang_Class/Class_getConstructor_A04; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getConstructor_Ljava_lang_Class.Class_getConstructor_A04" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 27) t27 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getFields/Class_getFields_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getFields.Class_getFields_A02" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -409,8 +409,8 @@ public class JctfTestSpecifications { // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getMethods/Class_getMethods_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getMethods.Class_getMethods_A02" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 30) t30 - // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getMethodLjava_lang_String$Ljava_lang_Class/Class_getMethod_A05; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String$Ljava_lang_Class.Class_getMethod_A05" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getMethodLjava_lang_String_Ljava_lang_Class/Class_getMethod_A05; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A05" on path: DexPathList[[dex file "/tmp/junit2603421343038865741/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 31) t31 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/SecurityManager/checkMemberAccessLjava_lang_ClassI/SecurityManager_checkMemberAccess_A02; @@ -593,8 +593,8 @@ public class JctfTestSpecifications { // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredConstructors.Class_getDeclaredConstructors_A02" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 3) t03 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> - // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredConstructor$Ljava_lang_Class/Class_getDeclaredConstructor_A03; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredConstructor$Ljava_lang_Class.Class_getDeclaredConstructor_A03" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredConstructor_Ljava_lang_Class/Class_getDeclaredConstructor_A03; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredConstructor_Ljava_lang_Class.Class_getDeclaredConstructor_A03" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 4) t04 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredFields/Class_getDeclaredFields_A02; @@ -609,8 +609,8 @@ public class JctfTestSpecifications { // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredMethods.Class_getDeclaredMethods_A02" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 7) t07 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> - // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredMethodLjava_lang_String$Ljava_lang_Class/Class_getDeclaredMethod_A05; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredMethodLjava_lang_String$Ljava_lang_Class.Class_getDeclaredMethod_A05" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredMethodLjava_lang_String_Ljava_lang_Class/Class_getDeclaredMethod_A05; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredMethodLjava_lang_String_Ljava_lang_Class.Class_getDeclaredMethod_A05" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 8) t08 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredClasses/Class_getDeclaredClasses_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredClasses.Class_getDeclaredClasses_A02" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -618,8 +618,8 @@ public class JctfTestSpecifications { // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredConstructors/Class_getDeclaredConstructors_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredConstructors.Class_getDeclaredConstructors_A02" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 10) t10 - // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredConstructor$Ljava_lang_Class/Class_getDeclaredConstructor_A03; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredConstructor$Ljava_lang_Class.Class_getDeclaredConstructor_A03" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredConstructor_Ljava_lang_Class/Class_getDeclaredConstructor_A03; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredConstructor_Ljava_lang_Class.Class_getDeclaredConstructor_A03" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 11) t11 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredFields/Class_getDeclaredFields_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredFields.Class_getDeclaredFields_A02" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -630,8 +630,8 @@ public class JctfTestSpecifications { // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredMethods/Class_getDeclaredMethods_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredMethods.Class_getDeclaredMethods_A02" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 14) t14 - // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredMethodLjava_lang_String$Ljava_lang_Class/Class_getDeclaredMethod_A05; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredMethodLjava_lang_String$Ljava_lang_Class.Class_getDeclaredMethod_A05" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getDeclaredMethodLjava_lang_String_Ljava_lang_Class/Class_getDeclaredMethod_A05; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getDeclaredMethodLjava_lang_String_Ljava_lang_Class.Class_getDeclaredMethod_A05" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 15) t15 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/newInstance/Class_newInstance_A07; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.newInstance.Class_newInstance_A07" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -649,8 +649,8 @@ public class JctfTestSpecifications { // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getConstructors.Class_getConstructors_A02" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 19) t19 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> - // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getConstructor$Ljava_lang_Class/Class_getConstructor_A04; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getConstructor$Ljava_lang_Class.Class_getConstructor_A04" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getConstructor_Ljava_lang_Class/Class_getConstructor_A04; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getConstructor_Ljava_lang_Class.Class_getConstructor_A04" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 20) t20 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getFields/Class_getFields_A02; @@ -665,8 +665,8 @@ public class JctfTestSpecifications { // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getMethods.Class_getMethods_A02" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 23) t23 // java.lang.Exception: Unexpected exception, expected<java.lang.SecurityException> but was<java.lang.NoClassDefFoundError> - // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getMethodLjava_lang_String$Ljava_lang_Class/Class_getMethod_A05; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String$Ljava_lang_Class.Class_getMethod_A05" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getMethodLjava_lang_String_Ljava_lang_Class/Class_getMethod_A05; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A05" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 24) t24 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getClasses/Class_getClasses_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getClasses.Class_getClasses_A02" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -674,8 +674,8 @@ public class JctfTestSpecifications { // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getConstructors/Class_getConstructors_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getConstructors.Class_getConstructors_A02" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 26) t26 - // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getConstructor$Ljava_lang_Class/Class_getConstructor_A04; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getConstructor$Ljava_lang_Class.Class_getConstructor_A04" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getConstructor_Ljava_lang_Class/Class_getConstructor_A04; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getConstructor_Ljava_lang_Class.Class_getConstructor_A04" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 27) t27 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getFields/Class_getFields_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getFields.Class_getFields_A02" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -686,8 +686,8 @@ public class JctfTestSpecifications { // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getMethods/Class_getMethods_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getMethods.Class_getMethods_A02" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 30) t30 - // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getMethodLjava_lang_String$Ljava_lang_Class/Class_getMethod_A05; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String$Ljava_lang_Class.Class_getMethod_A05" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/Class/getMethodLjava_lang_String_Ljava_lang_Class/Class_getMethod_A05; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A05" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 31) t32 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/SecurityManager/checkPackageAccessLjava_lang_String/SecurityManager_checkPackageAccess_A01; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.SecurityManager.checkPackageAccessLjava_lang_String.SecurityManager_checkPackageAccess_A01" on path: DexPathList[[dex file "/tmp/junit7609456538458065688/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -745,7 +745,7 @@ public class JctfTestSpecifications { // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/ClassLoader/ConstructorLjava_lang_ClassLoader/ClassLoader_Constructor_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.ClassLoader.ConstructorLjava_lang_ClassLoader.ClassLoader_Constructor_A02" on path: DexPathList[[dex file "/tmp/junit6765412840574788386/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] - .put("lang.ClassLoader.defineClassLjava_lang_String$BII.ClassLoader_defineClass_A06", + .put("lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A06", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference @@ -775,8 +775,8 @@ public class JctfTestSpecifications { // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/ThreadGroup/getParent/ThreadGroup_getParent_A03; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.ThreadGroup.getParent.ThreadGroup_getParent_A03" on path: DexPathList[[dex file "/tmp/junit7453598412317397853/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 8) t08 - // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/ThreadGroup/enumerate$ThreadGroup/ThreadGroup_enumerate_A03; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.ThreadGroup.enumerate$ThreadGroup.ThreadGroup_enumerate_A03" on path: DexPathList[[dex file "/tmp/junit7453598412317397853/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/ThreadGroup/enumerate_ThreadGroup/ThreadGroup_enumerate_A03; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.ThreadGroup.enumerate_ThreadGroup.ThreadGroup_enumerate_A03" on path: DexPathList[[dex file "/tmp/junit7453598412317397853/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 9) t09 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/ThreadGroup/interrupt/ThreadGroup_interrupt_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.ThreadGroup.interrupt.ThreadGroup_interrupt_A02" on path: DexPathList[[dex file "/tmp/junit7453598412317397853/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -799,8 +799,8 @@ public class JctfTestSpecifications { // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/ThreadGroup/getParent/ThreadGroup_getParent_A02; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.ThreadGroup.getParent.ThreadGroup_getParent_A02" on path: DexPathList[[dex file "/tmp/junit7453598412317397853/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 16) t16 - // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/ThreadGroup/enumerate$ThreadGroup/ThreadGroup_enumerate_A03; - // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.ThreadGroup.enumerate$ThreadGroup.ThreadGroup_enumerate_A03" on path: DexPathList[[dex file "/tmp/junit7453598412317397853/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] + // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/ThreadGroup/enumerate_ThreadGroup/ThreadGroup_enumerate_A03; + // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.ThreadGroup.enumerate_ThreadGroup.ThreadGroup_enumerate_A03" on path: DexPathList[[dex file "/tmp/junit7453598412317397853/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] // 17) t17 // java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/SecurityManager/checkAccessLjava_lang_ThreadGroup/SecurityManager_checkAccess_A01; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.SecurityManager.checkAccessLjava_lang_ThreadGroup.SecurityManager_checkAccess_A01" on path: DexPathList[[dex file "/tmp/junit7453598412317397853/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] @@ -809,12 +809,12 @@ public class JctfTestSpecifications { // Caused by: java.lang.NoClassDefFoundError: Failed resolution of: Lcom/google/jctf/test/lib/java/lang/SecurityManager/checkAccessLjava_lang_ThreadGroup/SecurityManager_checkAccess_A01; // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.SecurityManager.checkAccessLjava_lang_ThreadGroup.SecurityManager_checkAccess_A01" on path: DexPathList[[dex file "/tmp/junit7453598412317397853/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] - .put("lang.ClassLoader.defineClassLjava_lang_String$BII.ClassLoader_defineClass_A05", + .put("lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A05", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference - .put("lang.ClassLoader.defineClassLjava_lang_String$BII.ClassLoader_defineClass_A02", + .put("lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A02", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference @@ -823,26 +823,26 @@ public class JctfTestSpecifications { // 3) t03 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference - .put("lang.ClassLoader.defineClassLjava_lang_String$BII.ClassLoader_defineClass_A04", + .put("lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A04", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference // 2) t02 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference - .put("lang.ClassLoader.defineClassLjava_lang_String$BII.ClassLoader_defineClass_A03", + .put("lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A03", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference - .put("lang.ClassLoader.defineClassLjava_lang_String$BII.ClassLoader_defineClass_A01", + .put("lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A01", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference // 2) t02 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference - .put("lang.ClassLoader.defineClassLjava_lang_String$BII.ClassLoader_defineClass_A07", + .put("lang.ClassLoader.defineClassLjava_lang_String_BII.ClassLoader_defineClass_A07", any()) // 1) t01 // java.lang.Exception: Unexpected exception, expected<java.lang.NullPointerException> but was<java.lang.UnsupportedOperationException> @@ -969,7 +969,7 @@ public class JctfTestSpecifications { // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference .put( - "lang.ClassLoader.setSignersLjava_lang_Class$Ljava_lang_Object.ClassLoader_setSigners_A01", + "lang.ClassLoader.setSignersLjava_lang_Class_Ljava_lang_Object.ClassLoader_setSigners_A01", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference @@ -1025,7 +1025,7 @@ public class JctfTestSpecifications { // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.ClassLoader.findLoadedClassLjava_lang_String.TestLoader" on path: DexPathList[[dex file "/tmp/junit1789265657215742712/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] .put( - "lang.ClassLoader.defineClassLjava_lang_String$BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A02", + "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A02", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference @@ -1047,7 +1047,7 @@ public class JctfTestSpecifications { // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference .put( - "lang.ClassLoader.defineClassLjava_lang_String$BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A05", + "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A05", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference @@ -1055,7 +1055,7 @@ public class JctfTestSpecifications { // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference .put( - "lang.ClassLoader.defineClassLjava_lang_String$BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A01", + "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A01", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference @@ -1063,7 +1063,7 @@ public class JctfTestSpecifications { // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference .put( - "lang.ClassLoader.defineClassLjava_lang_String$BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A06", + "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A06", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference @@ -1071,14 +1071,14 @@ public class JctfTestSpecifications { // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference .put( - "lang.ClassLoader.defineClassLjava_lang_String$BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A08", + "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A08", any()) // 1) t01 // java.lang.Exception: Unexpected exception, expected<java.lang.NullPointerException> but was<java.lang.UnsupportedOperationException> // Caused by: java.lang.UnsupportedOperationException: can't load this type of class file .put( - "lang.ClassLoader.defineClassLjava_lang_String$BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A03", + "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A03", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference @@ -1098,25 +1098,25 @@ public class JctfTestSpecifications { // java.lang.AssertionError: Resource not found: .put( - "lang.ClassLoader.defineClassLjava_lang_String$BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A07", + "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A07", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference .put( - "lang.ClassLoader.defineClassLjava_lang_String$BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A09", + "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A09", any()) // 1) t01 // java.lang.Exception: Unexpected exception, expected<java.lang.NullPointerException> but was<java.lang.UnsupportedOperationException> // Caused by: java.lang.UnsupportedOperationException: can't load this type of class file .put( - "lang.ClassLoader.defineClassLjava_lang_String$BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A04", + "lang.ClassLoader.defineClassLjava_lang_String_BIILjava_security_ProtectionDomain.ClassLoader_defineClass_A04", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference - .put("lang.ClassLoader.defineClass$BII.ClassLoader_defineClass_A02", any()) + .put("lang.ClassLoader.defineClass_BII.ClassLoader_defineClass_A02", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference // 2) t02 @@ -1155,19 +1155,19 @@ public class JctfTestSpecifications { // 2) t02 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference - .put("lang.ClassLoader.defineClass$BII.ClassLoader_defineClass_A03", any()) + .put("lang.ClassLoader.defineClass_BII.ClassLoader_defineClass_A03", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference // 2) t02 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference - .put("lang.ClassLoader.defineClass$BII.ClassLoader_defineClass_A01", any()) + .put("lang.ClassLoader.defineClass_BII.ClassLoader_defineClass_A01", any()) // 1) t01 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference // 2) t02 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference - .put("lang.ClassLoader.defineClass$BII.ClassLoader_defineClass_A04", any()) + .put("lang.ClassLoader.defineClass_BII.ClassLoader_defineClass_A04", any()) // 1) t01 // java.lang.Exception: Unexpected exception, expected<java.lang.NullPointerException> but was<java.lang.UnsupportedOperationException> // Caused by: java.lang.UnsupportedOperationException: can't load this type of class file @@ -1293,16 +1293,16 @@ public class JctfTestSpecifications { // 2) t02 // java.lang.AssertionError - .put("lang.Runtime.exec$Ljava_lang_String.Runtime_exec_A02", any()) + .put("lang.Runtime.exec_Ljava_lang_String.Runtime_exec_A02", any()) // 1) t01 - // org.junit.ComparisonFailure: expected:<[t02]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.exec$Ljava_lang_String.Runtime_exec_A02$T01 + // org.junit.ComparisonFailure: expected:<[t02]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.exec_Ljava_lang_String.Runtime_exec_A02$T01 // ]> - .put("lang.Runtime.exec$Ljava_lang_String.Runtime_exec_A03", any()) + .put("lang.Runtime.exec_Ljava_lang_String.Runtime_exec_A03", any()) // 1) t01 // java.lang.AssertionError: expected:<0> but was:<1> - .put("lang.Runtime.exec$Ljava_lang_String.Runtime_exec_A01", any()) + .put("lang.Runtime.exec_Ljava_lang_String.Runtime_exec_A01", any()) // 1) t01 // org.junit.ComparisonFailure: expected:<[com google jctf test lib java lang Runtime]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.EchoArgs // ]> @@ -1408,19 +1408,19 @@ public class JctfTestSpecifications { // java.lang.AssertionError: Bad exit code of spawned java proccess, err=Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.addShutdownHookLjava_lang_Thread.Runtime_addShutdownHook_A06$T02 // expected:<0> but was:<1> - .put("lang.Runtime.execLjava_lang_String$Ljava_lang_String.Runtime_exec_A03", any()) + .put("lang.Runtime.execLjava_lang_String_Ljava_lang_String.Runtime_exec_A03", any()) // 1) t01 // java.lang.AssertionError: expected:<0> but was:<1> - .put("lang.Runtime.execLjava_lang_String$Ljava_lang_String.Runtime_exec_A02", any()) + .put("lang.Runtime.execLjava_lang_String_Ljava_lang_String.Runtime_exec_A02", any()) // 1) t01 // org.junit.ComparisonFailure: expected:<[t01]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.EchoEnv // ]> // 2) t02 - // org.junit.ComparisonFailure: expected:<[t02]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.execLjava_lang_String$Ljava_lang_String.Runtime_exec_A02$T02 + // org.junit.ComparisonFailure: expected:<[t02]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.execLjava_lang_String_Ljava_lang_String.Runtime_exec_A02$T02 // ]> - .put("lang.Runtime.execLjava_lang_String$Ljava_lang_String.Runtime_exec_A01", any()) + .put("lang.Runtime.execLjava_lang_String_Ljava_lang_String.Runtime_exec_A01", any()) // 1) t01 // org.junit.ComparisonFailure: expected:<[com google jctf test lib java lang Runtime]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.EchoArgs // ]> @@ -1434,7 +1434,7 @@ public class JctfTestSpecifications { // java.lang.AssertionError: Bad exit code of spawned java proccess, err=Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.removeShutdownHookLjava_lang_Thread.Runtime_removeShutdownHook_A02$T02 // expected:<0> but was:<1> - .put("lang.Runtime.exec$Ljava_lang_String$Ljava_lang_String.Runtime_exec_A01", any()) + .put("lang.Runtime.exec_Ljava_lang_String_Ljava_lang_String.Runtime_exec_A01", any()) // 1) t01 // org.junit.ComparisonFailure: expected:<[com google jctf test lib java lang Runtime]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.EchoArgs // ]> @@ -1444,12 +1444,12 @@ public class JctfTestSpecifications { // 1) t01 // java.lang.SecurityException - .put("lang.Runtime.exec$Ljava_lang_String$Ljava_lang_String.Runtime_exec_A02", any()) + .put("lang.Runtime.exec_Ljava_lang_String_Ljava_lang_String.Runtime_exec_A02", any()) // 1) t01 // org.junit.ComparisonFailure: expected:<[t01]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.EchoEnv // ]> // 2) t02 - // org.junit.ComparisonFailure: expected:<[t02]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.exec$Ljava_lang_String$Ljava_lang_String.Runtime_exec_A02$T02 + // org.junit.ComparisonFailure: expected:<[t02]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.exec_Ljava_lang_String$Ljava_lang_String.Runtime_exec_A02$T02 // ]> .put("lang.Runtime.removeShutdownHookLjava_lang_Thread.Runtime_removeShutdownHook_A03", @@ -1459,24 +1459,24 @@ public class JctfTestSpecifications { // expected:<0> but was:<1> .put( - "lang.Runtime.exec$Ljava_lang_String$Ljava_lang_StringLjava_io_File.Runtime_exec_A01", + "lang.Runtime.exec_Ljava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A01", any()) // 1) t01 // java.lang.AssertionError: actual=Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.EchoArgs // : array lengths differed, expected.length=8 actual.length=9 - .put("lang.Runtime.exec$Ljava_lang_String$Ljava_lang_String.Runtime_exec_A03", any()) + .put("lang.Runtime.exec_Ljava_lang_String_Ljava_lang_String.Runtime_exec_A03", any()) // 1) t01 // java.lang.AssertionError: expected:<0> but was:<1> .put( - "lang.Runtime.exec$Ljava_lang_String$Ljava_lang_StringLjava_io_File.Runtime_exec_A02", + "lang.Runtime.exec_Ljava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A02", any()) // 1) t01 // org.junit.ComparisonFailure: expected:<[t01]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.EchoEnv // ]> // 2) t02 - // org.junit.ComparisonFailure: expected:<[t02]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.exec$Ljava_lang_String$Ljava_lang_StringLjava_io_File.Runtime_exec_A02$T02 + // org.junit.ComparisonFailure: expected:<[t02]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.exec_Ljava_lang_String$Ljava_lang_StringLjava_io_File.Runtime_exec_A02$T02 // ]> .put("lang.Runtime.haltI.Runtime_halt_A02", any()) @@ -1488,7 +1488,7 @@ public class JctfTestSpecifications { // expected:<0> but was:<1> .put( - "lang.Runtime.exec$Ljava_lang_String$Ljava_lang_StringLjava_io_File.Runtime_exec_A03", + "lang.Runtime.exec_Ljava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A03", any()) // 1) t02 // java.lang.AssertionError: expected:<0> but was:<1> @@ -1541,12 +1541,12 @@ public class JctfTestSpecifications { // java.lang.AssertionError: Bad exit code of spawned java proccess, err=Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.runFinalizersOnExitZ.Runtime_runFinalizersOnExit_A03$T03 // expected:<0> but was:<1> - .put("lang.Runtime.execLjava_lang_String$Ljava_lang_StringLjava_io_File.Runtime_exec_A03", + .put("lang.Runtime.execLjava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A03", any()) // 1) t02 // java.lang.AssertionError: expected:<0> but was:<1> - .put("lang.Runtime.execLjava_lang_String$Ljava_lang_StringLjava_io_File.Runtime_exec_A01", + .put("lang.Runtime.execLjava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A01", any()) // 1) t01 // org.junit.ComparisonFailure: expected:<[com google jctf test lib java lang Runtime]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.EchoArgs @@ -1568,13 +1568,13 @@ public class JctfTestSpecifications { // java.lang.AssertionError: Process did not block but exited with code 1; // err=Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.exitI.Runtime_exit_A03$T03 - .put("lang.Runtime.execLjava_lang_String$Ljava_lang_StringLjava_io_File.Runtime_exec_A02", + .put("lang.Runtime.execLjava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A02", any()) // 1) t01 // org.junit.ComparisonFailure: expected:<[t01]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.EchoEnv // ]> // 2) t02 - // org.junit.ComparisonFailure: expected:<[t02]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.execLjava_lang_String$Ljava_lang_StringLjava_io_File.Runtime_exec_A02$T02 + // org.junit.ComparisonFailure: expected:<[t02]> but was:<[Error: Could not find or load main class com.google.jctf.test.lib.java.lang.Runtime.execLjava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A02$T02 // ]> .put("lang.Runtime.exitI.Runtime_exit_A04", any()) @@ -2178,7 +2178,7 @@ public class JctfTestSpecifications { // 2) t02 // java.lang.UnsupportedOperationException - .put("lang.ThreadGroup.enumerate$Thread.ThreadGroup_enumerate_A01", any()) + .put("lang.ThreadGroup.enumerate_Thread.ThreadGroup_enumerate_A01", any()) // 1) t05 // java.lang.UnsupportedOperationException @@ -2200,7 +2200,7 @@ public class JctfTestSpecifications { // 1) t01 // java.lang.SecurityException - .put("lang.ThreadGroup.enumerate$ThreadZ.ThreadGroup_enumerate_A01", any()) + .put("lang.ThreadGroup.enumerate_ThreadZ.ThreadGroup_enumerate_A01", any()) // 1) t06 // java.lang.UnsupportedOperationException @@ -2299,7 +2299,7 @@ public class JctfTestSpecifications { // 6) t07 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference - .put("lang.Class.getConstructor$Ljava_lang_Class.Class_getConstructor_A03", any()) + .put("lang.Class.getConstructor_Ljava_lang_Class.Class_getConstructor_A03", any()) // 1) t03 // java.lang.AssertionError: Vague error message @@ -2324,7 +2324,7 @@ public class JctfTestSpecifications { // java.lang.ClassNotFoundException: [[[Lcom.google.jctf.test.lib.java.lang.Class.forNameLjava_lang_StringZLjava_lang_ClassLoader.Class_forName_A01$TestFixture; // Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference - .put("lang.Class.getConstructor$Ljava_lang_Class.Class_getConstructor_A04", any()) + .put("lang.Class.getConstructor_Ljava_lang_Class.Class_getConstructor_A04", any()) // 1) t01 // java.lang.SecurityException // 2) t03 @@ -2347,7 +2347,7 @@ public class JctfTestSpecifications { // java.lang.SecurityException .put( - "lang.Class.getDeclaredMethodLjava_lang_String$Ljava_lang_Class.Class_getDeclaredMethod_A05", + "lang.Class.getDeclaredMethodLjava_lang_String_Ljava_lang_Class.Class_getDeclaredMethod_A05", any()) // 1) t01 // java.lang.SecurityException @@ -2365,7 +2365,7 @@ public class JctfTestSpecifications { // java.lang.SecurityException .put( - "lang.Class.getDeclaredMethodLjava_lang_String$Ljava_lang_Class.Class_getDeclaredMethod_A03", + "lang.Class.getDeclaredMethodLjava_lang_String_Ljava_lang_Class.Class_getDeclaredMethod_A03", any()) // 1) t05 // java.lang.AssertionError: Vague error message @@ -2546,10 +2546,10 @@ public class JctfTestSpecifications { // java.lang.NoClassDefFoundError: sun.security.jca.Providers // Caused by: java.lang.AssertionError: Unable to configure default providers - .put("lang.Class.getMethodLjava_lang_String$Ljava_lang_Class.Class_getMethod_A01", + .put("lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A01", match(runtimes(DexVm.ART_DEFAULT, DexVm.ART_7_0_0))) // 1) t04 - // java.lang.AssertionError: expected:<interface com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String$Ljava_lang_Class.Class_getMethod_A01$I1> but was:<interface com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String$Ljava_lang_Class.Class_getMethod_A01$I2> + // java.lang.AssertionError: expected:<interface com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A01$I1> but was:<interface com.google.jctf.test.lib.java.lang.Class.getMethodLjava_lang_String$Ljava_lang_Class.Class_getMethod_A01$I2> .put("lang.Class.getGenericSuperclass.Class_getGenericSuperclass_A01", any()) // 1) t03 @@ -2570,12 +2570,12 @@ public class JctfTestSpecifications { // java.lang.SecurityException .put( - "lang.Class.getDeclaredConstructor$Ljava_lang_Class.Class_getDeclaredConstructor_A02", + "lang.Class.getDeclaredConstructor_Ljava_lang_Class.Class_getDeclaredConstructor_A02", any()) // 1) t03 // java.lang.AssertionError: Vague error message - .put("lang.Class.getMethodLjava_lang_String$Ljava_lang_Class.Class_getMethod_A05", any()) + .put("lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A05", any()) // 1) t01 // java.lang.SecurityException // 2) t03 @@ -2590,7 +2590,7 @@ public class JctfTestSpecifications { // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference .put( - "lang.Class.getDeclaredConstructor$Ljava_lang_Class.Class_getDeclaredConstructor_A03", + "lang.Class.getDeclaredConstructor_Ljava_lang_Class.Class_getDeclaredConstructor_A03", any()) // 1) t01 // java.lang.SecurityException @@ -2599,7 +2599,7 @@ public class JctfTestSpecifications { // 3) t04 // java.lang.SecurityException - .put("lang.Class.getMethodLjava_lang_String$Ljava_lang_Class.Class_getMethod_A03", any()) + .put("lang.Class.getMethodLjava_lang_String_Ljava_lang_Class.Class_getMethod_A03", any()) // 1) t03 // java.lang.AssertionError: Vague error message @@ -2648,7 +2648,7 @@ public class JctfTestSpecifications { // 1) t09 // org.junit.ComparisonFailure: Incorrect double string returned expected:<0.001[0]> but was:<0.001[]> - .put("lang.String.Constructor$BLjava_nio_charset_Charset.String_Constructor_A01", any()) + .put("lang.String.Constructor_BLjava_nio_charset_Charset.String_Constructor_A01", any()) // 1) t02 // org.junit.ComparisonFailure: expected:<�[]> but was:<�[�]> // 2) t03 @@ -2701,13 +2701,13 @@ public class JctfTestSpecifications { // 1) t06 // java.lang.AssertionError: array lengths differed, expected.length=1 actual.length=2 - .put("lang.String.getBytesII$BI.String_getBytes_A03", any()) + .put("lang.String.getBytesII_BI.String_getBytes_A03", any()) // 1) t04 // java.lang.AssertionError: Should throws IndexOutOfBoundsException: 0 // 2) t05 // java.lang.AssertionError: Should throws IndexOutOfBoundsException: 0 - .put("lang.String.getBytesII$BI.String_getBytes_A02", any()) + .put("lang.String.getBytesII_BI.String_getBytes_A02", any()) // 1) t01 // java.lang.AssertionError: Expected exception: java.lang.NullPointerException @@ -2715,7 +2715,7 @@ public class JctfTestSpecifications { // 1) t02 // org.junit.ComparisonFailure: expected:<i[]> but was:<i[̇]> - .put("lang.String.Constructor$BIILjava_nio_charset_Charset.String_Constructor_A01", any()) + .put("lang.String.Constructor_BIILjava_nio_charset_Charset.String_Constructor_A01", any()) // 1) t02 // org.junit.ComparisonFailure: expected:<�[]> but was:<�[�]> // 2) t03 @@ -3609,7 +3609,7 @@ public class JctfTestSpecifications { // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference .put( - "lang.reflect.Proxy.getProxyClassLjava_lang_ClassLoader$Ljava_lang_Class.Proxy_getProxyClass_A01", + "lang.reflect.Proxy.getProxyClassLjava_lang_ClassLoader_Ljava_lang_Class.Proxy_getProxyClass_A01", any()) // 1) t01 // java.lang.AssertionError: expected same:<null> was not:<java.lang.BootClassLoader@ecc20b9> @@ -3617,7 +3617,7 @@ public class JctfTestSpecifications { // java.lang.AssertionError: expected same:<null> was not:<java.lang.BootClassLoader@ecc20b9> .put( - "lang.reflect.Proxy.getProxyClassLjava_lang_ClassLoader$Ljava_lang_Class.Proxy_getProxyClass_A03", + "lang.reflect.Proxy.getProxyClassLjava_lang_ClassLoader_Ljava_lang_Class.Proxy_getProxyClass_A03", any()) // 1) t03 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference @@ -3648,7 +3648,7 @@ public class JctfTestSpecifications { // java.lang.AssertionError: Failed to load serialization resource file: serialization/com/google/jctf/test/lib/java/lang/reflect/GenericSignatureFormatError/serialization/GenericSignatureFormatError_serialization_A01.golden.0.ser .put( - "lang.reflect.Proxy.newProxyInstanceLjava_lang_ClassLoader$Ljava_lang_ClassLjava_lang_reflect_InvocationHandler.Proxy_newProxyInstance_A02", + "lang.reflect.Proxy.newProxyInstanceLjava_lang_ClassLoader_Ljava_lang_ClassLjava_lang_reflect_InvocationHandler.Proxy_newProxyInstance_A02", any()) // 1) t03 // java.lang.NullPointerException: Attempt to invoke virtual method 'int java.io.InputStream.available()' on a null object reference @@ -3660,7 +3660,7 @@ public class JctfTestSpecifications { // java.lang.NullPointerException .put( - "lang.reflect.Proxy.newProxyInstanceLjava_lang_ClassLoader$Ljava_lang_ClassLjava_lang_reflect_InvocationHandler.Proxy_newProxyInstance_A01", + "lang.reflect.Proxy.newProxyInstanceLjava_lang_ClassLoader_Ljava_lang_ClassLjava_lang_reflect_InvocationHandler.Proxy_newProxyInstance_A01", any()) // 1) t01 // java.lang.AssertionError: Bad classloader expected:<null> but was:<java.lang.BootClassLoader@fda9ca7> @@ -3719,7 +3719,7 @@ public class JctfTestSpecifications { // java.lang.ClassNotFoundException: com.google.jctf.test.lib.java.lang.reflect.Method.getGenericExceptionTypes.Method_getGenericExceptionTypes_A01$Fourth // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.reflect.Method.getGenericExceptionTypes.Method_getGenericExceptionTypes_A01$Fourth" on path: DexPathList[[dex file "/tmp/junit8600081041276641493/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] - .put("lang.reflect.Method.invokeLjava_lang_Object$Ljava_lang_Object.Method_invoke_A07", + .put("lang.reflect.Method.invokeLjava_lang_Object_Ljava_lang_Object.Method_invoke_A07", any()) // 1) t01 // java.lang.AssertionError: Expected exception: java.lang.IllegalAccessException @@ -3772,7 +3772,7 @@ public class JctfTestSpecifications { // Caused by: java.lang.ClassNotFoundException: Didn't find class "com.google.jctf.test.lib.java.lang.reflect.Method.MissingParameterTypeMethod" on path: DexPathList[[dex file "/tmp/junit3534060116722105133/classes.dex"],nativeLibraryDirectories=[r8/tools/linux/art/bin/../lib, r8/tools/linux/art/bin/../lib]] .put( - "lang.reflect.InvocationHandler.invokeLjava_lang_ObjectLjava_lang_reflect_Method$Ljava_lang_Object.InvocationHandler_invoke_A02", + "lang.reflect.InvocationHandler.invokeLjava_lang_ObjectLjava_lang_reflect_Method_Ljava_lang_Object.InvocationHandler_invoke_A02", any()) // 1) t04 // java.lang.AssertionError: ClassCastException should be thrown @@ -4005,7 +4005,7 @@ public class JctfTestSpecifications { // 1) t02 // java.lang.AssertionError: Exception is not thrown: field: shortPublicField, object: com.google.jctf.test.lib.java.lang.reflect.Field.TestStaticFinalPrimitiveField@bf7ecde - .put("lang.reflect.Constructor.newInstance$Ljava_lang_Object.Constructor_newInstance_A06", + .put("lang.reflect.Constructor.newInstance_Ljava_lang_Object.Constructor_newInstance_A06", any()) // 1) t05 // java.lang.AssertionError: Expected exception: java.lang.IllegalArgumentException @@ -4125,7 +4125,7 @@ public class JctfTestSpecifications { // java.lang.SecurityException .put( - "lang.reflect.AccessibleObject.setAccessible$Ljava_lang_reflect_AccessibleObjectZ.AccessibleObject_setAccessible_A03", + "lang.reflect.AccessibleObject.setAccessible_Ljava_lang_reflect_AccessibleObjectZ.AccessibleObject_setAccessible_A03", any()) // 1) t01 // java.lang.SecurityException @@ -4139,7 +4139,7 @@ public class JctfTestSpecifications { // java.lang.AssertionError: Misconfiguration: MissingAntn should not be accessible .put( - "lang.reflect.AccessibleObject.setAccessible$Ljava_lang_reflect_AccessibleObjectZ.AccessibleObject_setAccessible_A02", + "lang.reflect.AccessibleObject.setAccessible_Ljava_lang_reflect_AccessibleObjectZ.AccessibleObject_setAccessible_A02", any()) // 1) t01 // java.lang.SecurityException @@ -4452,7 +4452,7 @@ public class JctfTestSpecifications { // 2) t02(com.google.jctf.test.lib.java.util.concurrent.CopyOnWriteArrayList.lastIndexOfLjava_lang_ObjectI.CopyOnWriteArrayList_lastIndexOf_A01) // java.lang.ArrayIndexOutOfBoundsException: length=3; index=2147483647 - .put("lang.StringBuffer.getCharsII$CI.StringBuffer_getChars_A03", + .put("lang.StringBuffer.getCharsII_CI.StringBuffer_getChars_A03", match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1))) // 1) t03 // java.lang.NullPointerException: dst == null @@ -4462,7 +4462,7 @@ public class JctfTestSpecifications { // 1) t02 // java.lang.AssertionError: Buffer is invalid length after append expected:<26> but was:<25> - .put("lang.StringBuffer.insertI$CII.StringBuffer_insert_A02", + .put("lang.StringBuffer.insertI_CII.StringBuffer_insert_A02", match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1))) // 1) t01 // java.lang.NullPointerException: Attempt to get length of null array @@ -4623,7 +4623,7 @@ public class JctfTestSpecifications { // java.lang.AssertionError: Invalid length of created builder expected:<14> but was:<13> .put( - "lang.reflect.AccessibleObject.setAccessible$Ljava_lang_reflect_AccessibleObjectZ.AccessibleObject_setAccessible_A04", + "lang.reflect.AccessibleObject.setAccessible_Ljava_lang_reflect_AccessibleObjectZ.AccessibleObject_setAccessible_A04", match(runtimes(DexVm.ART_6_0_1, DexVm.ART_5_1_1))) // 1) t01 // java.lang.AssertionError: SecurityException expected. @@ -4745,34 +4745,34 @@ public class JctfTestSpecifications { any()) .put("lang.Thread.setPriorityI.Thread_setPriority_A02", any()) .put("lang.Thread.stopLjava_lang_Throwable.Thread_stop_A02", any()) - .put("lang.Runtime.execLjava_lang_String$Ljava_lang_StringLjava_io_File.Runtime_exec_A04", + .put("lang.Runtime.execLjava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A04", any()) .put("lang.Thread.getContextClassLoader.Thread_getContextClassLoader_A02", any()) .put("lang.ThreadGroup.suspend.ThreadGroup_suspend_A02", any()) .put("lang.Thread.setDaemonZ.Thread_setDaemon_A03", any()) .put("lang.ProcessBuilder.environment.ProcessBuilder_environment_A07", any()) .put( - "lang.Runtime.exec$Ljava_lang_String$Ljava_lang_StringLjava_io_File.Runtime_exec_A04", + "lang.Runtime.exec_Ljava_lang_String_Ljava_lang_StringLjava_io_File.Runtime_exec_A04", any()) - .put("lang.Runtime.execLjava_lang_String$Ljava_lang_String.Runtime_exec_A04", any()) - .put("lang.Runtime.exec$Ljava_lang_String.Runtime_exec_A04", any()) + .put("lang.Runtime.execLjava_lang_String_Ljava_lang_String.Runtime_exec_A04", any()) + .put("lang.Runtime.exec_Ljava_lang_String.Runtime_exec_A04", any()) .put("lang.Runtime.execLjava_lang_String.Runtime_exec_A04", any()) .put("lang.System.clearPropertyLjava_lang_String.System_clearProperty_A03", any()) .put("lang.System.getSecurityManager.System_getSecurityManager_A01", any()) .put("lang.System.setInLjava_io_InputStream.System_setIn_A02", any()) .put("lang.System.setOutLjava_io_PrintStream.System_setOut_A02", any()) .put("lang.ThreadGroup.destroy.ThreadGroup_destroy_A04", any()) - .put("lang.ThreadGroup.enumerate$ThreadGroupZ.ThreadGroup_enumerate_A03", any()) - .put("lang.ThreadGroup.enumerate$Thread.ThreadGroup_enumerate_A03", any()) - .put("lang.ThreadGroup.enumerate$ThreadZ.ThreadGroup_enumerate_A03", any()) + .put("lang.ThreadGroup.enumerate_ThreadGroupZ.ThreadGroup_enumerate_A03", any()) + .put("lang.ThreadGroup.enumerate_Thread.ThreadGroup_enumerate_A03", any()) + .put("lang.ThreadGroup.enumerate_ThreadZ.ThreadGroup_enumerate_A03", any()) .put("lang.ThreadGroup.interrupt.ThreadGroup_interrupt_A02", any()) .put("lang.ThreadGroup.resume.ThreadGroup_resume_A02", any()) .put("lang.ThreadGroup.setMaxPriorityI.ThreadGroup_setMaxPriority_A02", any()) - .put("lang.Runtime.exec$Ljava_lang_String$Ljava_lang_String.Runtime_exec_A04", any()) + .put("lang.Runtime.exec_Ljava_lang_String_Ljava_lang_String.Runtime_exec_A04", any()) .put("lang.System.getenvLjava_lang_String.System_getenv_A03", any()) .put("lang.System.setPropertyLjava_lang_StringLjava_lang_String.System_setProperty_A02", any()) - .put("lang.ThreadGroup.enumerate$ThreadGroup.ThreadGroup_enumerate_A03", any()) + .put("lang.ThreadGroup.enumerate_ThreadGroup.ThreadGroup_enumerate_A03", any()) .put("lang.ThreadGroup.getParent.ThreadGroup_getParent_A02", any()) .put("lang.ThreadGroup.setDaemonZ.ThreadGroup_setDaemon_A02", any()) .put("lang.ThreadGroup.stop.ThreadGroup_stop_A02", any()) diff --git a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java index 0d0446d85..22278e2aa 100644 --- a/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java +++ b/src/test/java/com/android/tools/r8/R8RunArtTestsTest.java @@ -96,6 +96,7 @@ public abstract class R8RunArtTestsTest { private static Map<String, Integer> needMinSdkVersion = new ImmutableMap.Builder<String, Integer>() // Android O + .put("952-invoke-custom", Constants.ANDROID_O_API) .put("953-invoke-polymorphic-compiler", Constants.ANDROID_O_API) .put("957-methodhandle-transforms", Constants.ANDROID_O_API) .put("958-methodhandle-stackframe", Constants.ANDROID_O_API) @@ -218,37 +219,25 @@ public abstract class R8RunArtTestsTest { "073-mismatched-field" ); - // Tests that make use of Java 8 features. - private static List<String> usesJava8 = ImmutableList.of( - "914-hello-obsolescence", - "915-obsolete-2", - "916-obsolete-jit", - "919-obsolete-fields", - "926-multi-obsolescence", - "936-search-onload", - "940-recursive-obsolete", - "941-recurive-obsolete-jit", - "942-private-recursive", - "943-private-recursive-jit", - "946-obsolete-throw", - "951-threaded-obsolete", - "952-invoke-custom" - ); - // Tests that make use of agents/native code. Our test setup does handle flags/linking of these. private static List<String> usesNativeAgentCode = ImmutableList.of( "497-inlining-and-class-loader", "626-const-class-linking", "642-fp-callees", "909-attach-agent", + "914-hello-obsolescence", + "915-obsolete-2", + "916-obsolete-jit", "917-fields-transformation", "918-fields", + "919-obsolete-fields", "920-objects", "921-hello-failure", "922-properties", "923-monitors", "924-threads", "925-threadgroups", + "926-multi-obsolescence", "927-timers", "928-jni-table", "929-search", @@ -262,12 +251,18 @@ public abstract class R8RunArtTestsTest { "937-hello-retransform-package", "938-load-transform-bcp", "939-hello-transformation-bcp", + "940-recursive-obsolete", + "941-recurive-obsolete-jit", + "942-private-recursive", + "943-private-recursive-jit", "944-transform-classloaders", "945-obsolete-native", + "946-obsolete-throw", "947-reflect-method", "948-change-annotations", "949-in-memory-transform", "950-redefine-intrinsic", + "951-threaded-obsolete", "980-redefine-object" ); @@ -630,6 +625,9 @@ public abstract class R8RunArtTestsTest { // is in dex code which D8 does not convert. Therefore the error is a verification error // at runtime and that is expected. .put("142-classloader2", TestCondition.match(TestCondition.D8_COMPILER)) + // Invoke-custom is supported by D8 and R8, but it can only run on our newest version + // of art. + .put("952-invoke-custom", beforeAndroidO) // Invoke-polymorphic is supported by D8 and R8, but it can only run on our newest version // of art. .put("953-invoke-polymorphic-compiler", beforeAndroidO) @@ -734,6 +732,17 @@ public abstract class R8RunArtTestsTest { .build()) .build(); + // Tests to skip on some conditions + private static final Multimap<String, TestCondition> testToSkip = + new ImmutableListMultimap.Builder<String, TestCondition>() + // Old runtimes used the legacy test directory which does not contain input for tools + // NONE and DX. + .put("952-invoke-custom", TestCondition.match( + TestCondition.tools(DexTool.NONE, DexTool.DX), + TestCondition.runtimes( + DexVm.ART_4_4_4, DexVm.ART_5_1_1, DexVm.ART_6_0_1, DexVm.ART_7_0_0))) + .build(); + private static List<String> failuresToTriage = ImmutableList.of( // This is flaky. "104-growth-limit", @@ -896,7 +905,6 @@ public abstract class R8RunArtTestsTest { skipArt.addAll(customRun); Set<String> skipTest = Sets.newHashSet(skipAltogether); - skipTest.addAll(usesJava8); skipTest.addAll(usesNativeAgentCode); skipTest.addAll(failuresToTriage); @@ -915,6 +923,10 @@ public abstract class R8RunArtTestsTest { skipTest.addAll(noInputJar); } + // Collect the test that we should skip in this configuration + skipTest.addAll(collectTestsMatchingConditions( + dexTool, compilerUnderTest, dexVm, compilationMode, testToSkip)); + // Collect the test that we should skip in this configuration. skipArt.addAll( collectTestsMatchingConditions( diff --git a/src/test/java/com/android/tools/r8/compatdx/CompatDxTests.java b/src/test/java/com/android/tools/r8/compatdx/CompatDxTests.java index b3d31c54c..5af5c0c1d 100644 --- a/src/test/java/com/android/tools/r8/compatdx/CompatDxTests.java +++ b/src/test/java/com/android/tools/r8/compatdx/CompatDxTests.java @@ -100,10 +100,21 @@ public class CompatDxTests { } @Test + public void singleDexProgramFull() throws IOException, ExecutionException { + // Generate an application that fills the whole dex file. + AndroidApp generated = + MainDexListTests.generateApplication( + ImmutableList.of("A"), Constants.ANDROID_L_API, Constants.U16BIT_MAX + 1); + Path applicationJar = temp.newFile("application.jar").toPath(); + generated.write(applicationJar, OutputMode.Indexed); + runDexer(applicationJar.toString()); + } + + @Test public void singleDexProgramIsTooLarge() throws IOException, ExecutionException { // Generate an application that will not fit into a single dex file. AndroidApp generated = MainDexListTests.generateApplication( - ImmutableList.of("A", "B"), Constants.ANDROID_L_API, Constants.U16BIT_MAX / 2 + 1); + ImmutableList.of("A", "B"), Constants.ANDROID_L_API, Constants.U16BIT_MAX / 2 + 2); Path applicationJar = temp.newFile("application.jar").toPath(); generated.write(applicationJar, OutputMode.Indexed); thrown.expect(CompilationError.class); diff --git a/src/test/java/com/android/tools/r8/debug/ContinuousSteppingTest.java b/src/test/java/com/android/tools/r8/debug/ContinuousSteppingTest.java new file mode 100644 index 000000000..ad94a531b --- /dev/null +++ b/src/test/java/com/android/tools/r8/debug/ContinuousSteppingTest.java @@ -0,0 +1,38 @@ +// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. + +package com.android.tools.r8.debug; + +import java.util.Map; +import org.apache.harmony.jpda.tests.framework.jdwp.Value; +import org.junit.Assert; +import org.junit.Test; + +public class ContinuousSteppingTest extends DebugTestBase { + + @Test + public void testArithmetic() throws Throwable { + runContinuousTest("Arithmetic"); + } + + @Test + public void testLocals() throws Throwable { + runContinuousTest("Locals"); + } + + private void runContinuousTest(String debuggeeClassName) throws Throwable { + runDebugTest(debuggeeClassName, + breakpoint(debuggeeClassName, "main"), + run(), + stepUntil(StepKind.OVER, StepLevel.INSTRUCTION, debuggeeState -> { + // Fetch local variables. + Map<String, Value> localValues = debuggeeState.getLocalValues(); + Assert.assertNotNull(localValues); + + // Always step until we actually exit the program. + return false; + })); + } + +} diff --git a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java index a272eca6c..be2509780 100644 --- a/src/test/java/com/android/tools/r8/debug/DebugTestBase.java +++ b/src/test/java/com/android/tools/r8/debug/DebugTestBase.java @@ -18,10 +18,10 @@ import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.Deque; import java.util.List; import java.util.Map; import java.util.Optional; -import java.util.Queue; import java.util.TreeMap; import java.util.function.Consumer; import java.util.function.Function; @@ -341,7 +341,7 @@ public abstract class DebugTestBase { */ private DebuggeeState debuggeeState = null; - private final Queue<Command> commandsQueue; + private final Deque<Command> commandsQueue; // Active event requests. private final Map<Integer, EventHandler> events = new TreeMap<>(); @@ -473,6 +473,9 @@ public abstract class DebugTestBase { artCommandBuilder.appendArtOption("-Xcompiler-option"); artCommandBuilder.appendArtOption("--compiler-filter=interpret-only"); } + if (DEBUG_TESTS) { + artCommandBuilder.appendArtOption("-verbose:jdwp"); + } setProperty("jpda.settings.debuggeeJavaPath", artCommandBuilder.build()); } @@ -1031,8 +1034,8 @@ public abstract class DebugTestBase { stepRequestID = replyPacket.getNextValueAsInt(); testBase.assertAllDataRead(replyPacket); } - testBase.events.put(stepRequestID, new StepEventHandler(stepRequestID, stepFilter, - stepUntil)); + testBase.events + .put(stepRequestID, new StepEventHandler(this, stepRequestID, stepFilter, stepUntil)); // Resume all threads. testBase.resume(); @@ -1092,13 +1095,17 @@ public abstract class DebugTestBase { private static class StepEventHandler extends DefaultEventHandler { + private final JUnit3Wrapper.Command.StepCommand stepCommand; private final int stepRequestID; private final StepFilter stepFilter; private final Function<DebuggeeState, Boolean> stepUntil; - private StepEventHandler(int stepRequestID, + private StepEventHandler( + JUnit3Wrapper.Command.StepCommand stepCommand, + int stepRequestID, StepFilter stepFilter, Function<DebuggeeState, Boolean> stepUntil) { + this.stepCommand = stepCommand; this.stepRequestID = stepRequestID; this.stepFilter = stepFilter; this.stepUntil = stepUntil; @@ -1106,19 +1113,23 @@ public abstract class DebugTestBase { @Override public void handle(JUnit3Wrapper testBase) { + // Clear step event. + testBase.getMirror().clearEvent(EventKind.SINGLE_STEP, stepRequestID); + testBase.events.remove(Integer.valueOf(stepRequestID)); + + // Do we need to step again ? + boolean repeatStep = false; if (stepFilter .skipLocation(testBase.getMirror(), testBase.getDebuggeeState().getLocation())) { - // Keep the step active and resume so that we do another step. - testBase.resume(); + repeatStep = true; } else if (stepUntil.apply(testBase.getDebuggeeState()) == Boolean.FALSE) { - // We must not stop yet. - testBase.resume(); - } else { - // When hit, the single step must be cleared. - testBase.getMirror().clearEvent(EventKind.SINGLE_STEP, stepRequestID); - testBase.events.remove(Integer.valueOf(stepRequestID)); - super.handle(testBase); + repeatStep = true; + } + if (repeatStep) { + // In order to repeat the step now, we need to add it at the beginning of the queue. + testBase.commandsQueue.addFirst(stepCommand); } + super.handle(testBase); } } diff --git a/src/test/java/com/android/tools/r8/ir/deterministic/DeterministicProcessingTest.java b/src/test/java/com/android/tools/r8/ir/deterministic/DeterministicProcessingTest.java index 6acacdaee..d5f70cce6 100644 --- a/src/test/java/com/android/tools/r8/ir/deterministic/DeterministicProcessingTest.java +++ b/src/test/java/com/android/tools/r8/ir/deterministic/DeterministicProcessingTest.java @@ -70,7 +70,7 @@ public class DeterministicProcessingTest extends SmaliTestBase { public List<DexEncodedMethod> permutationsOfTwo( List<DexEncodedMethod> methods, CallGraph.Leaves leaves) { - if (!leaves.brokeCycles()) { + if (!leaves.hasBrokeCycles()) { return methods; } methods.sort(Comparator.comparing(DexEncodedMethod::qualifiedName)); diff --git a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java index 05b06af78..242a7d5a4 100644 --- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java +++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java @@ -18,9 +18,7 @@ import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.ExpectedException; public class ProguardConfigurationParserTest extends TestBase { @@ -47,7 +45,7 @@ public class ProguardConfigurationParserTest extends TestBase { private static final String LIBRARY_JARS = VALID_PROGUARD_DIR + "library-jars.flags"; private static final String LIBRARY_JARS_WIN = - VALID_PROGUARD_DIR + "library-jars-win.flags"; + VALID_PROGUARD_DIR + "library-jars-win.flags"; private static final String SEEDS = VALID_PROGUARD_DIR + "seeds.flags"; private static final String SEEDS_2 = @@ -58,6 +56,8 @@ public class ProguardConfigurationParserTest extends TestBase { VALID_PROGUARD_DIR + "keepdirectories.flags"; private static final String DONT_OBFUSCATE = VALID_PROGUARD_DIR + "dontobfuscate.flags"; + private static final String DONT_SHRINK = + VALID_PROGUARD_DIR + "dontshrink.flags"; private static final String DONT_SKIP_NON_PUBLIC_LIBRARY_CLASSES = VALID_PROGUARD_DIR + "dontskipnonpubliclibraryclasses.flags"; private static final String DONT_SKIP_NON_PUBLIC_LIBRARY_CLASS_MEMBERS = @@ -70,12 +70,13 @@ public class ProguardConfigurationParserTest extends TestBase { VALID_PROGUARD_DIR + "skipnonpubliclibraryclasses.flags"; private static final String PARSE_AND_SKIP_SINGLE_ARGUMENT = VALID_PROGUARD_DIR + "parse-and-skip-single-argument.flags"; + private static final String PRINT_USAGE = + VALID_PROGUARD_DIR + "printusage.flags"; + private static final String PRINT_USAGE_TO_FILE = + VALID_PROGUARD_DIR + "printusage-to-file.flags"; private static final String TARGET = VALID_PROGUARD_DIR + "target.flags"; - @Rule - public ExpectedException thrown = ExpectedException.none(); - @Test public void parse() throws IOException, ProguardRuleParserException { ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory()); @@ -327,6 +328,14 @@ public class ProguardConfigurationParserTest extends TestBase { } @Test + public void parseDontshrink() throws IOException, ProguardRuleParserException { + ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory()); + parser.parse(Paths.get(DONT_SHRINK)); + ProguardConfiguration config = parser.getConfig(); + assertFalse(config.isShrinking()); + } + + @Test public void parseDontSkipNonPublicLibraryClasses() throws IOException, ProguardRuleParserException { ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory()); @@ -355,12 +364,14 @@ public class ProguardConfigurationParserTest extends TestBase { } @Test - public void parseSkipNonPublicLibraryClasses() - throws IOException, ProguardRuleParserException { - thrown.expect(ProguardRuleParserException.class); - thrown.expectMessage("Unsupported option: -skipnonpubliclibraryclasses"); - ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory()); - parser.parse(Paths.get(SKIP_NON_PUBLIC_LIBRARY_CLASSES)); + public void parseSkipNonPublicLibraryClasses() throws IOException { + try { + ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory()); + parser.parse(Paths.get(SKIP_NON_PUBLIC_LIBRARY_CLASSES)); + fail(); + } catch (ProguardRuleParserException e) { + assertTrue(e.getMessage().contains("Unsupported option: -skipnonpubliclibraryclasses")); + } } @Test @@ -370,6 +381,24 @@ public class ProguardConfigurationParserTest extends TestBase { } @Test + public void parsePrintUsage() throws IOException, ProguardRuleParserException { + ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory()); + parser.parse(Paths.get(PRINT_USAGE)); + ProguardConfiguration config = parser.getConfig(); + assertTrue(config.isPrintUsage()); + assertNull(config.getPrintUsageFile()); + } + + @Test + public void parsePrintUsageToFile() throws IOException, ProguardRuleParserException { + ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory()); + parser.parse(Paths.get(PRINT_USAGE_TO_FILE)); + ProguardConfiguration config = parser.getConfig(); + assertTrue(config.isPrintUsage()); + assertNotNull(config.getPrintUsageFile()); + } + + @Test public void parseTarget() throws IOException, ProguardRuleParserException { ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory()); @@ -378,15 +407,18 @@ public class ProguardConfigurationParserTest extends TestBase { @Test public void parseInvalidKeepClassOption() throws IOException, ProguardRuleParserException { - thrown.expect(ProguardRuleParserException.class); - thrown.expectMessage("Unknown option at "); - ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory()); - Path proguardConfig = writeTextToTempFile( - "-keepclassx public class * { ", - " native <methods>; ", - "} " - ); - parser.parse(proguardConfig); + try { + ProguardConfigurationParser parser = new ProguardConfigurationParser(new DexItemFactory()); + Path proguardConfig = writeTextToTempFile( + "-keepclassx public class * { ", + " native <methods>; ", + "} " + ); + parser.parse(proguardConfig); + fail(); + } catch (ProguardRuleParserException e) { + assertTrue(e.getMessage().contains("Unknown option at ")); + } } @Test diff --git a/src/test/java/com/android/tools/r8/utils/D8CommandTest.java b/src/test/java/com/android/tools/r8/utils/D8CommandTest.java index 2844a22de..1db48c4fc 100644 --- a/src/test/java/com/android/tools/r8/utils/D8CommandTest.java +++ b/src/test/java/com/android/tools/r8/utils/D8CommandTest.java @@ -163,6 +163,12 @@ public class D8CommandTest { parse("--output", invalidType.toString()); } + @Test + public void nonExistingOutputJar() throws Throwable { + Path nonExistingJar = temp.getRoot().toPath().resolve("non-existing-archive.jar"); + D8Command.builder().setOutputPath(nonExistingJar).build(); + } + private D8Command parse(String... args) throws IOException, CompilationException { return D8Command.parse(args).build(); } diff --git a/src/test/java/com/android/tools/r8/utils/OutputModeTest.java b/src/test/java/com/android/tools/r8/utils/OutputModeTest.java new file mode 100644 index 000000000..5929b6073 --- /dev/null +++ b/src/test/java/com/android/tools/r8/utils/OutputModeTest.java @@ -0,0 +1,34 @@ +// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file +// for details. All rights reserved. Use of this source code is governed by a +// BSD-style license that can be found in the LICENSE file. +package com.android.tools.r8.utils; + +import static org.junit.Assert.assertEquals; + +import com.android.tools.r8.Resource; +import java.util.Collections; +import org.junit.Test; + +public class OutputModeTest { + @Test + public void testIndexedFileName() { + assertEquals("classes.dex", OutputMode.Indexed.getOutputPath(null, 0)); + assertEquals("classes2.dex", OutputMode.Indexed.getOutputPath(null, 1)); + } + + @Test + public void testFilePerClass() { + Resource test = + Resource.fromBytes(Resource.Kind.CLASSFILE, new byte[]{}, Collections.singleton("LTest;")); + assertEquals("Test.dex", OutputMode.FilePerClass.getOutputPath(test, 0)); + Resource comTest = + Resource.fromBytes( + Resource.Kind.CLASSFILE, new byte[]{}, Collections.singleton("Lcom/Test;")); + assertEquals("com/Test.dex", OutputMode.FilePerClass.getOutputPath(comTest, 0)); + Resource comExampleTest = + Resource.fromBytes( + Resource.Kind.CLASSFILE, new byte[]{}, Collections.singleton("Lcom/example/Test;")); + assertEquals("com/example/Test.dex", OutputMode.FilePerClass.getOutputPath(comExampleTest, 0)); + assertEquals("com/example/Test.dex", OutputMode.FilePerClass.getOutputPath(comExampleTest, 1)); + } +} diff --git a/src/test/java/com/android/tools/r8/utils/R8CommandTest.java b/src/test/java/com/android/tools/r8/utils/R8CommandTest.java index ed38b888a..2af79cbcf 100644 --- a/src/test/java/com/android/tools/r8/utils/R8CommandTest.java +++ b/src/test/java/com/android/tools/r8/utils/R8CommandTest.java @@ -184,6 +184,12 @@ public class R8CommandTest { assertEquals(1, ToolHelper.getApp(command).getDexProgramResources().size()); } + @Test + public void nonExistingOutputJar() throws Throwable { + Path nonExistingJar = temp.getRoot().toPath().resolve("non-existing-archive.jar"); + R8Command.builder().setOutputPath(nonExistingJar).build(); + } + private R8Command parse(String... args) throws CompilationException, ProguardRuleParserException, IOException { return R8Command.parse(args).build(); diff --git a/src/test/proguard/valid/dontshrink.flags b/src/test/proguard/valid/dontshrink.flags new file mode 100644 index 000000000..3d7dbaa3c --- /dev/null +++ b/src/test/proguard/valid/dontshrink.flags @@ -0,0 +1,5 @@ +# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +-dontshrink diff --git a/src/test/proguard/valid/printusage-to-file.flags b/src/test/proguard/valid/printusage-to-file.flags new file mode 100644 index 000000000..c3dcdc5b6 --- /dev/null +++ b/src/test/proguard/valid/printusage-to-file.flags @@ -0,0 +1,5 @@ +# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +-printusage ~/tmp/random_output_file.txt diff --git a/src/test/proguard/valid/printusage.flags b/src/test/proguard/valid/printusage.flags new file mode 100644 index 000000000..2606411da --- /dev/null +++ b/src/test/proguard/valid/printusage.flags @@ -0,0 +1,5 @@ +# Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file +# for details. All rights reserved. Use of this source code is governed by a +# BSD-style license that can be found in the LICENSE file. + +-printusage diff --git a/third_party/gradle/gradle.tar.gz.sha1 b/third_party/gradle/gradle.tar.gz.sha1 index 60fe88df5..008d84c90 100644 --- a/third_party/gradle/gradle.tar.gz.sha1 +++ b/third_party/gradle/gradle.tar.gz.sha1 @@ -1 +1 @@ -6d7736db6f3f9c2dbe57e1ea6b36a1f694b9feef +1d118f48ff995b7eca95f3655293ea959779a6c0
\ No newline at end of file diff --git a/third_party/jctf.tar.gz.sha1 b/third_party/jctf.tar.gz.sha1 index 35ec1ba1e..41e1ea9dd 100644 --- a/third_party/jctf.tar.gz.sha1 +++ b/third_party/jctf.tar.gz.sha1 @@ -1 +1 @@ -93c13a164ca54db72273642d27308e325526fd38
\ No newline at end of file +d824506dedb8cb186a13d2fd45aae349ce86bcad
\ No newline at end of file diff --git a/tools/proguard.py b/tools/proguard.py index 58c049f9e..efcf560d2 100755 --- a/tools/proguard.py +++ b/tools/proguard.py @@ -15,10 +15,13 @@ import utils PROGUARD_JAR = os.path.join(utils.REPO_ROOT, 'third_party', 'proguard', 'proguard_internal_159423826', 'ProGuard_deploy.jar') -def run(args): - cmd = ['java', '-jar', PROGUARD_JAR] +def run(args, track_memory_file = None): + cmd = [] + if track_memory_file: + cmd.extend(['tools/track_memory.sh', track_memory_file]) + cmd.extend(['java', '-jar', PROGUARD_JAR]) cmd.extend(args) - print('-- ' + ' '.join(cmd)) + utils.PrintCmd(cmd) subprocess.check_call(cmd) def Main(): diff --git a/tools/run_on_app.py b/tools/run_on_app.py index f3cc9b5ca..d7db7fb16 100755 --- a/tools/run_on_app.py +++ b/tools/run_on_app.py @@ -3,6 +3,7 @@ # 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. +from __future__ import print_function import optparse import os import sys @@ -55,8 +56,11 @@ def ParseOptions(): 'If passing several options use a quoted string.') result.add_option('--r8-flags', help='Additional option(s) for the compiler. ' + - 'Same as --compiler-flags, keeping it for backward compatibility. ' + + 'Same as --compiler-flags, keeping it for backward' + ' compatibility. ' + 'If passing several options use a quoted string.') + # TODO(tamaskenez) remove track-memory-to-file as soon as we updated golem + # to use --print-memoryuse instead result.add_option('--track-memory-to-file', help='Track how much memory the jvm is using while ' + ' compiling. Output to the specified file.') @@ -73,6 +77,11 @@ def ParseOptions(): help='Prints the line \'<BENCHMARKNAME>(RunTimeRaw):' + ' <elapsed> ms\' at the end where <elapsed> is' + ' the elapsed time in milliseconds.') + result.add_option('--print-memoryuse', + metavar='BENCHMARKNAME', + help='Prints the line \'<BENCHMARKNAME>(MemoryUse):' + + ' <mem>\' at the end where <mem> is the peak' + + ' peak resident set size (VmHWM) in bytes.') return result.parse_args() # Most apps have the -printmapping and -printseeds in the Proguard @@ -81,10 +90,10 @@ def ParseOptions(): # placing these two output files together with the dex output. def GenerateAdditionalProguardConfiguration(temp, outdir): name = "output.config" - with open(os.path.join(temp, name), 'w') as file: - file.write('-printmapping ' + os.path.join(outdir, 'proguard.map') + "\n") - file.write('-printseeds ' + os.path.join(outdir, 'proguard.seeds') + "\n") - return os.path.abspath(file.name) + with open(os.path.join(temp, name), 'w') as f: + f.write('-printmapping ' + os.path.join(outdir, 'proguard.map') + "\n") + f.write('-printseeds ' + os.path.join(outdir, 'proguard.seeds') + "\n") + return os.path.abspath(f.name) def main(): app_provided_pg_conf = False; @@ -104,8 +113,9 @@ def main(): raise 'Unexpected' if not options.version in data.VERSIONS.keys(): - print 'No version %s for application %s' % (options.version, options.app) - print 'Valid versions are %s' % data.VERSIONS.keys() + print('No version {} for application {}' + .format(options.version, options.app)) + print('Valid versions are {}'.format(data.VERSIONS.keys())) return 1 version = data.VERSIONS[options.version] @@ -115,13 +125,15 @@ def main(): else 'proguarded' if options.type not in version: - print 'No type %s for version %s' % (options.type, options.version) - print 'Valid types are %s' % version.keys() + print('No type {} for version {}'.format(options.type, options.version)) + print('Valid types are {}'.format(version.keys())) return 1 values = version[options.type] inputs = None - # For R8 'deploy' the JAR is located using the Proguard configuration -injars option. - if 'inputs' in values and (options.compiler != 'r8' or options.type != 'deploy'): + # For R8 'deploy' the JAR is located using the Proguard configuration + # -injars option. + if 'inputs' in values and (options.compiler != 'r8' + or options.type != 'deploy'): inputs = values['inputs'] args.extend(['--output', outdir]) @@ -145,7 +157,8 @@ def main(): for lib in values['libraries']: args.extend(['--lib', lib]) - if not outdir.endswith('.zip') and not outdir.endswith('.jar') and not os.path.exists(outdir): + if not outdir.endswith('.zip') and not outdir.endswith('.jar') \ + and not os.path.exists(outdir): os.makedirs(outdir) if options.compiler == 'r8': @@ -161,16 +174,18 @@ def main(): args.extend(inputs) t0 = time.time() - if options.dump_args_file: with open(options.dump_args_file, 'w') as args_file: args_file.writelines([arg + os.linesep for arg in args]) else: - if options.compiler == 'd8': - d8.run(args, not options.no_build, not options.no_debug, options.profile, - options.track_memory_to_file) - else: - with utils.TempDir() as temp: + with utils.TempDir() as temp: + if options.print_memoryuse and not options.track_memory_to_file: + options.track_memory_to_file = os.path.join(temp, + utils.MEMORY_USE_TMP_FILE) + if options.compiler == 'd8': + d8.run(args, not options.no_build, not options.no_debug, + options.profile, options.track_memory_to_file) + else: if app_provided_pg_conf: # Ensure that output of -printmapping and -printseeds go to the output # location and not where the app Proguard configuration places them. @@ -181,8 +196,12 @@ def main(): additional_pg_conf = GenerateAdditionalProguardConfiguration( temp, os.path.abspath(pg_outdir)) args.extend(['--pg-conf', additional_pg_conf]) - r8.run(args, not options.no_build, not options.no_debug, options.profile, - options.track_memory_to_file) + r8.run(args, not options.no_build, not options.no_debug, + options.profile, options.track_memory_to_file) + if options.print_memoryuse: + print('{}(MemoryUse): {}' + .format(options.print_memoryuse, + utils.grep_memoryuse(options.track_memory_to_file))) if options.print_runtimeraw: print('{}(RunTimeRaw): {} ms' diff --git a/tools/run_proguard_dx_on_gmscore.py b/tools/run_proguard_dx_on_gmscore.py index ca0b5e9e9..de716b082 100755 --- a/tools/run_proguard_dx_on_gmscore.py +++ b/tools/run_proguard_dx_on_gmscore.py @@ -40,6 +40,11 @@ def parse_arguments(): help = 'Prints the line \'<BENCHMARKNAME>(RunTimeRaw): <elapsed>' + ' ms\' at the end where <elapsed> is the elapsed time in' + ' milliseconds.') + parser.add_argument('--print-memoryuse', + metavar='BENCHMARKNAME', + help='Prints the line \'<BENCHMARKNAME>(MemoryUse):' + + ' <mem>\' at the end where <mem> is the peak' + + ' peak resident set size (VmHWM) in bytes.') parser.add_argument('--compatdx', help = 'Use CompatDx (D8) instead of DX.', default = False, @@ -72,7 +77,15 @@ def Main(): t0 = time.time() - proguard.run(args) + proguard_memoryuse = None + + with utils.TempDir() as temp: + track_memory_file = None + if options.print_memoryuse: + track_memory_file = join(temp, utils.MEMORY_USE_TMP_FILE) + proguard.run(args, track_memory_file = track_memory_file) + if options.print_memoryuse: + proguard_memoryuse = utils.grep_memoryuse(track_memory_file) # run dex on the result if options.compatdx: @@ -80,10 +93,21 @@ def Main(): else: jar = DX_JAR - cmd = ['java', '-jar', jar, '--min-sdk-version=26', '--multi-dex', - '--output=' + outdir, '--dex', PROGUARDED_OUTPUT]; - utils.PrintCmd(cmd); - check_call(cmd) + with utils.TempDir() as temp: + track_memory_file = None + cmd = [] + if options.print_memoryuse: + track_memory_file = join(temp, utils.MEMORY_USE_TMP_FILE) + cmd.extend(['tools/track_memory.sh', track_memory_file]) + cmd.extend(['java', '-jar', jar, '--min-sdk-version=26', '--multi-dex', + '--output=' + outdir, '--dex', PROGUARDED_OUTPUT]); + utils.PrintCmd(cmd); + check_call(cmd) + if options.print_memoryuse: + dx_memoryuse = utils.grep_memoryuse(track_memory_file) + print('{}(MemoryUse): {}' + .format(options.print_memoryuse, + max(proguard_memoryuse, dx_memoryuse))) if options.print_runtimeraw: print('{}(RunTimeRaw): {} ms' diff --git a/tools/test_framework.py b/tools/test_framework.py index 810935d18..57279bfb4 100755 --- a/tools/test_framework.py +++ b/tools/test_framework.py @@ -53,6 +53,12 @@ def parse_arguments(): required = True, help = 'Results will be printed using the specified benchmark name (e.g.' ' <NAME>-<segment>(CodeSize): <bytes>)') + parser.add_argument('--print-memoryuse', + help = 'Prints the line \'<NAME>(MemoryUse):' + + ' <mem>\' at the end where <mem> is the peak' + + ' peak resident set size (VmHWM) in bytes.', + default = False, + action = 'store_true') return parser.parse_args() # Return a dictionary: {segment_name -> segments_size} @@ -96,10 +102,16 @@ def Main(): if args.tool == 'd8-release': tool_args.append('--release') + + cmd = [] + + track_memory_file = None + if args.print_memoryuse: + track_memory_file = os.path.join(temp_dir, utils.MEMORY_USE_TMP_FILE) + cmd.extend(['tools/track_memory.sh', track_memory_file]) + if tool_file.endswith('.jar'): - cmd = ['java', '-jar'] - else: - cmd = [] + cmd.extend(['java', '-jar']) cmd.extend([tool_file] + tool_args + [FRAMEWORK_JAR]) @@ -109,6 +121,10 @@ def Main(): subprocess.check_call(cmd) dt = time.time() - t0 + if args.print_memoryuse: + print('{}(MemoryUse): {}' + .format(args.name, utils.grep_memoryuse(track_memory_file))) + dex_files = [f for f in glob(os.path.join(temp_dir, '*.dex'))] code_size = 0 for dex_file in dex_files: diff --git a/tools/utils.py b/tools/utils.py index fd7212bd7..2564adc2e 100644 --- a/tools/utils.py +++ b/tools/utils.py @@ -14,6 +14,7 @@ import tempfile TOOLS_DIR = os.path.abspath(os.path.normpath(os.path.join(__file__, '..'))) REPO_ROOT = os.path.realpath(os.path.join(TOOLS_DIR, '..')) +MEMORY_USE_TMP_FILE = 'memory_use.tmp' def PrintCmd(s): if type(s) is list: @@ -118,3 +119,25 @@ def read_cts_test_result(file_xml): outcome = m.groups()[0] assert outcome in ['fail', 'pass'] yield CtsTest(m.groups()[1], outcome == 'pass') + +def grep_memoryuse(logfile): + re_vmhwm = re.compile('^VmHWM:[ \t]*([0-9]+)[ \t]*([a-zA-Z]*)') + result = None + with open(logfile) as f: + for line in f: + m = re_vmhwm.search(line) + if m: + groups = m.groups() + s = len(groups) + if s >= 1: + result = int(groups[0]) + if s >= 2: + unit = groups[1] + if unit == 'kB': + result *= 1024 + elif unit != '': + raise Exception('Unrecognized unit in memory usage log: {}' + .format(unit)) + if result is None: + raise Exception('No memory usage found in log: {}'.format(logfile)) + return result
\ No newline at end of file |