Merge "Remove rules for services for building r8 processed r8 jars"
diff --git a/infra/config/global/luci-notify.cfg b/infra/config/global/luci-notify.cfg
index 07cc8b5..1c59f19 100644
--- a/infra/config/global/luci-notify.cfg
+++ b/infra/config/global/luci-notify.cfg
@@ -8,7 +8,7 @@
notifications {
on_change: false
on_success: false
- on_failure: false
+ on_failure: true
on_new_failure: true
email {
# Temporary, to ensure that it works.
@@ -19,177 +19,177 @@
}
builders {
name: "archive"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "archive_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux-android-4.0.4"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux-android-4.0.4_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux-android-4.4.4"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux-android-4.4.4_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux-android-5.1.1"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux-android-5.1.1_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux-android-6.0.1"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux-android-6.0.1_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux-android-7.0.0"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux-android-7.0.0_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux-jctf"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux-jctf_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "d8-linux_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-android-4.0.4"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-android-4.0.4_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-android-4.4.4"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-android-4.4.4_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-android-5.1.1"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-android-5.1.1_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-android-6.0.1"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-android-6.0.1_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-android-7.0.0"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-android-7.0.0_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-internal"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-internal_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-jctf"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "linux-jctf_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "r8cf-linux-jctf"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "windows"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
builders {
name: "windows_release"
- bucket: "ci"
+ bucket: "luci.r8.ci"
repository: "https://r8.googlesource.com/r8"
}
}
diff --git a/src/main/java/com/android/tools/r8/PrintClassList.java b/src/main/java/com/android/tools/r8/PrintClassList.java
index ea43a00..40cdf2e 100644
--- a/src/main/java/com/android/tools/r8/PrintClassList.java
+++ b/src/main/java/com/android/tools/r8/PrintClassList.java
@@ -76,7 +76,7 @@
// Detour via Signature to get the same formatting.
FieldSignature signature = new FieldSignature(field.name.toSourceString(),
field.type.toSourceString());
- System.out.println(field.clazz.toSourceString() + " " + signature);
+ System.out.println(field.holder.toSourceString() + " " + signature);
}
}
diff --git a/src/main/java/com/android/tools/r8/PrintUses.java b/src/main/java/com/android/tools/r8/PrintUses.java
index b12e26f..f2d2143 100644
--- a/src/main/java/com/android/tools/r8/PrintUses.java
+++ b/src/main/java/com/android/tools/r8/PrintUses.java
@@ -175,13 +175,13 @@
addType(field.type);
DexEncodedField baseField =
isStatic
- ? appInfo.lookupStaticTarget(field.clazz, field)
- : appInfo.lookupInstanceTarget(field.clazz, field);
- if (baseField != null && baseField.field.clazz != field.clazz) {
+ ? appInfo.lookupStaticTarget(field.holder, field)
+ : appInfo.lookupInstanceTarget(field.holder, field);
+ if (baseField != null && baseField.field.holder != field.holder) {
field = baseField.field;
}
- addType(field.clazz);
- Set<DexField> typeFields = fields.get(field.clazz);
+ addType(field.holder);
+ Set<DexField> typeFields = fields.get(field.holder);
if (typeFields != null) {
typeFields.add(field);
}
diff --git a/src/main/java/com/android/tools/r8/ResourceShrinker.java b/src/main/java/com/android/tools/r8/ResourceShrinker.java
index 6267db1..21e4f10 100644
--- a/src/main/java/com/android/tools/r8/ResourceShrinker.java
+++ b/src/main/java/com/android/tools/r8/ResourceShrinker.java
@@ -233,11 +233,11 @@
private void processAnnotations(DexProgramClass classDef) {
Stream<DexAnnotation> instanceFieldAnnotations =
- Arrays.stream(classDef.instanceFields())
+ classDef.instanceFields().stream()
.filter(DexEncodedField::hasAnnotation)
.flatMap(f -> Arrays.stream(f.annotations.annotations));
Stream<DexAnnotation> staticFieldAnnotations =
- Arrays.stream(classDef.staticFields())
+ classDef.staticFields().stream()
.filter(DexEncodedField::hasAnnotation)
.flatMap(f -> Arrays.stream(f.annotations.annotations));
Stream<DexAnnotation> virtualMethodAnnotations =
@@ -411,7 +411,7 @@
throw new AssertionError("Not a get static instruction");
}
- callback.referencedStaticField(field.clazz.getInternalName(), field.name.toString());
+ callback.referencedStaticField(field.holder.getInternalName(), field.name.toString());
}
private boolean isInvokeInstruction(Instruction instruction) {
diff --git a/src/main/java/com/android/tools/r8/Version.java b/src/main/java/com/android/tools/r8/Version.java
index f35021b..1cda441 100644
--- a/src/main/java/com/android/tools/r8/Version.java
+++ b/src/main/java/com/android/tools/r8/Version.java
@@ -11,7 +11,7 @@
// This field is accessed from release scripts using simple pattern matching.
// Therefore, changing this field could break our release scripts.
- public static final String LABEL = "1.5.10-dev";
+ public static final String LABEL = "1.5.11-dev";
private Version() {
}
diff --git a/src/main/java/com/android/tools/r8/cf/CfPrinter.java b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
index 1f62c88..97a9aaf 100644
--- a/src/main/java/com/android/tools/r8/cf/CfPrinter.java
+++ b/src/main/java/com/android/tools/r8/cf/CfPrinter.java
@@ -710,7 +710,7 @@
builder.append(mapper.originalSignatureOf(field).toString());
return;
}
- appendClass(field.getHolder());
+ appendClass(field.holder);
builder.append('/').append(field.name);
}
diff --git a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
index 4bf9e04..d84f551 100644
--- a/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
+++ b/src/main/java/com/android/tools/r8/cf/TypeVerificationHelper.java
@@ -239,8 +239,8 @@
if (argumentIndex < 0) {
argumentType =
code.method.isInstanceInitializer()
- ? new ThisInstanceInfo(instruction.asArgument(), code.method.method.getHolder())
- : createInitializedType(code.method.method.getHolder());
+ ? new ThisInstanceInfo(instruction.asArgument(), code.method.method.holder)
+ : createInitializedType(code.method.method.holder);
} else {
argumentType =
createInitializedType(code.method.method.proto.parameters.values[argumentIndex]);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index 350c1c9..4f05d38 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -39,7 +39,7 @@
@Override
public void write(MethodVisitor visitor, NamingLens lens) {
- String owner = lens.lookupInternalName(field.getHolder());
+ String owner = lens.lookupInternalName(field.holder);
String name = lens.lookupName(declaringField).toString();
String desc = lens.lookupDescriptor(field.type).toString();
visitor.visitFieldInsn(opcode, owner, name, desc);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index c8749fe..233fc01 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -51,7 +51,7 @@
@Override
public void write(MethodVisitor visitor, NamingLens lens) {
- String owner = lens.lookupInternalName(method.getHolder());
+ String owner = lens.lookupInternalName(method.holder);
String name = lens.lookupName(method).toString();
String desc = method.proto.toDescriptorString(lens);
visitor.visitMethodInsn(opcode, owner, name, desc, itf);
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 7b2c688..ab06751 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -26,6 +26,7 @@
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexEncodedArray;
+import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
@@ -49,7 +50,7 @@
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
-import java.util.LinkedHashMap;
+import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@@ -227,77 +228,58 @@
SortAnnotations sortAnnotations = new SortAnnotations();
application.classes().forEach((clazz) -> clazz.addDependencies(sortAnnotations));
- // Collect the indexed items sets for all files and perform JumboString processing.
- // This is required to ensure that shared code blocks have a single and consistent code
- // item that is valid for all dex files.
- // Use a linked hash map as the order matters when addDexProgramData is called below.
- Map<VirtualFile, Future<ObjectToOffsetMapping>> offsetMappingFutures = new LinkedHashMap<>();
- for (VirtualFile newFile : distribute(executorService)) {
- if (!newFile.isEmpty()) {
- offsetMappingFutures
- .put(newFile, executorService.submit(() -> {
- ObjectToOffsetMapping mapping = newFile.computeMapping(application);
- rewriteCodeWithJumboStrings(mapping, newFile.classes(), application);
- return mapping;
- }));
- }
- }
-
- // Wait for all spawned futures to terminate to ensure jumbo string writing is complete.
- ThreadUtils.awaitFutures(offsetMappingFutures.values());
-
// Generate the dex file contents.
List<Future<Boolean>> dexDataFutures = new ArrayList<>();
- try {
- for (VirtualFile virtualFile : offsetMappingFutures.keySet()) {
- assert !virtualFile.isEmpty();
- final ObjectToOffsetMapping mapping = offsetMappingFutures.get(virtualFile).get();
- dexDataFutures.add(
- executorService.submit(
- () -> {
- ProgramConsumer consumer;
- ByteBufferProvider byteBufferProvider;
- if (programConsumer != null) {
- consumer = programConsumer;
- byteBufferProvider = programConsumer;
- } else if (virtualFile.getPrimaryClassDescriptor() != null) {
- consumer = options.getDexFilePerClassFileConsumer();
- byteBufferProvider = options.getDexFilePerClassFileConsumer();
- } else {
- consumer = options.getDexIndexedConsumer();
- byteBufferProvider = options.getDexIndexedConsumer();
- }
- ByteBufferResult result = writeDexFile(mapping, byteBufferProvider);
- ByteDataView data =
- new ByteDataView(
- result.buffer.array(), result.buffer.arrayOffset(), result.length);
- if (consumer instanceof DexFilePerClassFileConsumer) {
- ((DexFilePerClassFileConsumer) consumer)
- .accept(
- virtualFile.getPrimaryClassDescriptor(),
- data,
- virtualFile.getClassDescriptors(),
- options.reporter);
- } else {
- ((DexIndexedConsumer) consumer)
- .accept(
- virtualFile.getId(),
- data,
- virtualFile.getClassDescriptors(),
- options.reporter);
- }
- // Release use of the backing buffer now that accept has returned.
- data.invalidate();
- byteBufferProvider.releaseByteBuffer(result.buffer.asByteBuffer());
- return true;
- }));
+ Iterable<VirtualFile> virtualFiles = distribute(executorService);
+ for (VirtualFile virtualFile : virtualFiles) {
+ if (virtualFile.isEmpty()) {
+ continue;
}
- } catch (InterruptedException e) {
- throw new RuntimeException("Interrupted while waiting for future.", e);
+ dexDataFutures.add(
+ executorService.submit(
+ () -> {
+ ProgramConsumer consumer;
+ ByteBufferProvider byteBufferProvider;
+ if (programConsumer != null) {
+ consumer = programConsumer;
+ byteBufferProvider = programConsumer;
+ } else if (virtualFile.getPrimaryClassDescriptor() != null) {
+ consumer = options.getDexFilePerClassFileConsumer();
+ byteBufferProvider = options.getDexFilePerClassFileConsumer();
+ } else {
+ consumer = options.getDexIndexedConsumer();
+ byteBufferProvider = options.getDexIndexedConsumer();
+ }
+ ObjectToOffsetMapping objectMapping = virtualFile.computeMapping(application);
+ MethodToCodeObjectMapping codeMapping =
+ rewriteCodeWithJumboStrings(
+ objectMapping, virtualFile.classes(), application);
+ ByteBufferResult result =
+ writeDexFile(objectMapping, codeMapping, byteBufferProvider);
+ ByteDataView data =
+ new ByteDataView(
+ result.buffer.array(), result.buffer.arrayOffset(), result.length);
+ if (consumer instanceof DexFilePerClassFileConsumer) {
+ ((DexFilePerClassFileConsumer) consumer)
+ .accept(
+ virtualFile.getPrimaryClassDescriptor(),
+ data,
+ virtualFile.getClassDescriptors(),
+ options.reporter);
+ } else {
+ ((DexIndexedConsumer) consumer)
+ .accept(
+ virtualFile.getId(),
+ data,
+ virtualFile.getClassDescriptors(),
+ options.reporter);
+ }
+ // Release use of the backing buffer now that accept has returned.
+ data.invalidate();
+ byteBufferProvider.releaseByteBuffer(result.buffer.asByteBuffer());
+ return true;
+ }));
}
-
- // Clear out the map, as it is no longer needed.
- offsetMappingFutures.clear();
// Wait for all files to be processed before moving on.
ThreadUtils.awaitFutures(dexDataFutures);
// Fail if there are pending errors, e.g., the program consumers may have reported errors.
@@ -482,36 +464,58 @@
}
/**
- * Rewrites the code for all methods in the given file so that they use JumboString for at
- * least the strings that require it in mapping.
- * <p>
- * If run multiple times on a class, the lowest index that is required to be a JumboString will
+ * Rewrites the code for all methods in the given file so that they use JumboString for at least
+ * the strings that require it in mapping.
+ *
+ * <p>If run multiple times on a class, the lowest index that is required to be a JumboString will
* be used.
*/
- private void rewriteCodeWithJumboStrings(ObjectToOffsetMapping mapping,
- Collection<DexProgramClass> classes, DexApplication application) {
+ private MethodToCodeObjectMapping rewriteCodeWithJumboStrings(
+ ObjectToOffsetMapping mapping,
+ Collection<DexProgramClass> classes,
+ DexApplication application) {
// Do not bail out early if forcing jumbo string processing.
if (!options.testing.forceJumboStringProcessing) {
// If there are no strings with jumbo indices at all this is a no-op.
if (!mapping.hasJumboStrings()) {
- return;
+ return MethodToCodeObjectMapping.fromMethodBacking();
}
// If the globally highest sorting string is not a jumbo string this is also a no-op.
if (application.highestSortingString != null &&
application.highestSortingString.slowCompareTo(mapping.getFirstJumboString()) < 0) {
- return;
+ return MethodToCodeObjectMapping.fromMethodBacking();
}
}
- // At least one method needs a jumbo string.
+ // At least one method needs a jumbo string in which case we construct a thread local mapping
+ // for all code objects and write the processed results into that map.
+ Map<DexEncodedMethod, DexCode> codeMapping = new IdentityHashMap<>();
for (DexProgramClass clazz : classes) {
- clazz.forEachMethod(method -> method.rewriteCodeWithJumboStrings(
- mapping, application, options.testing.forceJumboStringProcessing));
+ boolean isSharedSynthetic = clazz.getSynthesizedFrom().size() > 1;
+ clazz.forEachMethod(
+ method -> {
+ DexCode code =
+ method.rewriteCodeWithJumboStrings(
+ mapping,
+ application.dexItemFactory,
+ options.testing.forceJumboStringProcessing);
+ codeMapping.put(method, code);
+ if (!isSharedSynthetic) {
+ // If the class is not a shared class the mapping now has ownership of the methods
+ // code object. This ensures freeing of code resources once the map entry is cleared
+ // and also ensures that we don't end up using the incorrect code pointer again later!
+ method.removeCode();
+ }
+ });
}
+ return MethodToCodeObjectMapping.fromMapBacking(codeMapping);
}
private ByteBufferResult writeDexFile(
- ObjectToOffsetMapping mapping, ByteBufferProvider provider) {
- FileWriter fileWriter = new FileWriter(provider, mapping, application, options, namingLens);
+ ObjectToOffsetMapping objectMapping,
+ MethodToCodeObjectMapping codeMapping,
+ ByteBufferProvider provider) {
+ FileWriter fileWriter =
+ new FileWriter(provider, objectMapping, codeMapping, application, options, namingLens);
// Collect the non-fixed sections.
fileWriter.collect();
// Generate and write the bytes.
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 4197da5..c9b8ffc 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -58,7 +58,7 @@
import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import java.security.MessageDigest;
-import java.util.Arrays;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
@@ -86,6 +86,7 @@
}
private final ObjectToOffsetMapping mapping;
+ private final MethodToCodeObjectMapping codeMapping;
private final DexApplication application;
private final InternalOptions options;
private final NamingLens namingLens;
@@ -95,19 +96,21 @@
public FileWriter(
ByteBufferProvider provider,
ObjectToOffsetMapping mapping,
+ MethodToCodeObjectMapping codeMapping,
DexApplication application,
InternalOptions options,
NamingLens namingLens) {
this.mapping = mapping;
+ this.codeMapping = codeMapping;
this.application = application;
this.options = options;
this.namingLens = namingLens;
this.dest = new DexOutputBuffer(provider);
- this.mixedSectionOffsets = new MixedSectionOffsets(options);
+ this.mixedSectionOffsets = new MixedSectionOffsets(options, codeMapping);
}
- public static void writeEncodedAnnotation(DexEncodedAnnotation annotation, DexOutputBuffer dest,
- ObjectToOffsetMapping mapping) {
+ public static void writeEncodedAnnotation(
+ DexEncodedAnnotation annotation, DexOutputBuffer dest, ObjectToOffsetMapping mapping) {
if (Log.ENABLED) {
Log.verbose(FileWriter.class, "Writing encoded annotation @ %08x", dest.position());
}
@@ -154,8 +157,11 @@
Layout layout = Layout.from(mapping);
layout.setCodesOffset(layout.dataSectionOffset);
+ // Check code objects in the code-mapping are consistent with the collected code objects.
+ assert codeMapping.verifyCodeObjects(mixedSectionOffsets.getCodes());
+
// Sort the codes first, as their order might impact size due to alignment constraints.
- List<DexCode> codes = sortDexCodesByClassName(mixedSectionOffsets.getCodes(), application);
+ List<DexCode> codes = sortDexCodesByClassName();
// Output the debug_info_items first, as they have no dependencies.
dest.moveTo(layout.getCodesOffset() + sizeOfCodeItems(codes));
@@ -276,35 +282,40 @@
}
}
- private List<DexCode> sortDexCodesByClassName(Collection<DexCode> codes,
- DexApplication application) {
+ private List<DexCode> sortDexCodesByClassName() {
Map<DexCode, String> codeToSignatureMap = new IdentityHashMap<>();
+ List<DexCode> codesSorted = new ArrayList<>();
for (DexProgramClass clazz : mapping.getClasses()) {
- clazz.forEachMethod(method ->
- addSignaturesFromMethod(method, codeToSignatureMap, application.getProguardMap()));
+ clazz.forEachMethod(
+ method -> {
+ DexCode code = codeMapping.getCode(method);
+ assert code != null || method.shouldNotHaveCode();
+ if (code != null) {
+ codesSorted.add(code);
+ addSignaturesFromMethod(
+ method, code, codeToSignatureMap, application.getProguardMap());
+ }
+ });
}
- DexCode[] codesArray = codes.toArray(new DexCode[codes.size()]);
- Arrays.sort(codesArray, Comparator.comparing(codeToSignatureMap::get));
- return Arrays.asList(codesArray);
+ codesSorted.sort(Comparator.comparing(codeToSignatureMap::get));
+ return codesSorted;
}
- private static void addSignaturesFromMethod(DexEncodedMethod method,
+ private static void addSignaturesFromMethod(
+ DexEncodedMethod method,
+ DexCode code,
Map<DexCode, String> codeToSignatureMap,
ClassNameMapper proguardMap) {
- if (!method.hasCode()) {
- assert method.shouldNotHaveCode();
+ Signature signature;
+ String originalClassName;
+ if (proguardMap != null) {
+ signature = proguardMap.originalSignatureOf(method.method);
+ originalClassName = proguardMap.originalNameOf(method.method.holder);
} else {
- Signature signature;
- String originalClassName;
- if (proguardMap != null) {
- signature = proguardMap.originalSignatureOf(method.method);
- originalClassName = proguardMap.originalNameOf(method.method.holder);
- } else {
- signature = MethodSignature.fromDexMethod(method.method);
- originalClassName = method.method.holder.toSourceString();
- }
- codeToSignatureMap.put(method.getCode().asDexCode(), originalClassName + signature);
+ signature = MethodSignature.fromDexMethod(method.method);
+ originalClassName = method.method.holder.toSourceString();
}
+ codeToSignatureMap.put(code, originalClassName + signature);
}
private <T extends IndexedDexItem> void writeFixedSectionItems(
@@ -394,7 +405,7 @@
}
private void writeFieldItem(DexField field) {
- int classIdx = mapping.getOffsetFor(field.clazz);
+ int classIdx = mapping.getOffsetFor(field.holder);
assert (classIdx & 0xFFFF) == classIdx;
dest.putShort((short) classIdx);
int typeIdx = mapping.getOffsetFor(field.type);
@@ -561,8 +572,8 @@
item -> mixedSectionOffsets.getOffsetFor(item.parameterAnnotationsList));
}
- private void writeEncodedFields(DexEncodedField[] fields) {
- assert PresortedComparable.isSorted(Arrays.asList(fields));
+ private void writeEncodedFields(List<DexEncodedField> fields) {
+ assert PresortedComparable.isSorted(fields);
int currentOffset = 0;
for (DexEncodedField field : fields) {
int nextOffset = mapping.getOffsetFor(field.field);
@@ -573,7 +584,7 @@
}
}
- private void writeEncodedMethods(List<DexEncodedMethod> methods, boolean clearBodies) {
+ private void writeEncodedMethods(List<DexEncodedMethod> methods, boolean isSharedSynthetic) {
assert PresortedComparable.isSorted(methods);
int currentOffset = 0;
for (DexEncodedMethod method : methods) {
@@ -582,16 +593,15 @@
dest.putUleb128(nextOffset - currentOffset);
currentOffset = nextOffset;
dest.putUleb128(method.accessFlags.getAsDexAccessFlags());
- if (!method.hasCode()) {
+ DexCode code = codeMapping.getCode(method);
+ if (code == null) {
assert method.shouldNotHaveCode();
dest.putUleb128(0);
} else {
- dest.putUleb128(mixedSectionOffsets.getOffsetFor(method.getCode().asDexCode()));
+ dest.putUleb128(mixedSectionOffsets.getOffsetFor(code));
// Writing the methods starts to take up memory so we are going to flush the
// code objects since they are no longer necessary after this.
- if (clearBodies) {
- method.removeCode();
- }
+ codeMapping.clearCode(method, isSharedSynthetic);
}
}
}
@@ -599,16 +609,15 @@
private void writeClassData(DexProgramClass clazz) {
assert clazz.hasMethodsOrFields();
mixedSectionOffsets.setOffsetFor(clazz, dest.position());
- dest.putUleb128(clazz.staticFields().length);
- dest.putUleb128(clazz.instanceFields().length);
+ dest.putUleb128(clazz.staticFields().size());
+ dest.putUleb128(clazz.instanceFields().size());
dest.putUleb128(clazz.directMethods().size());
dest.putUleb128(clazz.virtualMethods().size());
writeEncodedFields(clazz.staticFields());
writeEncodedFields(clazz.instanceFields());
-
boolean isSharedSynthetic = clazz.getSynthesizedFrom().size() > 1;
- writeEncodedMethods(clazz.directMethods(), !isSharedSynthetic);
- writeEncodedMethods(clazz.virtualMethods(), !isSharedSynthetic);
+ writeEncodedMethods(clazz.directMethods(), isSharedSynthetic);
+ writeEncodedMethods(clazz.virtualMethods(), isSharedSynthetic);
}
private void addStaticFieldValues(DexProgramClass clazz) {
@@ -1001,6 +1010,8 @@
private static final int NOT_SET = -1;
private static final int NOT_KNOWN = -2;
+ private final MethodToCodeObjectMapping codeMapping;
+
private final Reference2IntMap<DexCode> codes = createReference2IntMap();
private final Object2IntMap<DexDebugInfo> debugInfos = createObject2IntMap();
private final Object2IntMap<DexTypeList> typeLists = createObject2IntMap();
@@ -1030,8 +1041,9 @@
return result;
}
- private MixedSectionOffsets(InternalOptions options) {
+ private MixedSectionOffsets(InternalOptions options, MethodToCodeObjectMapping codeMapping) {
this.minApiLevel = options.minApiLevel;
+ this.codeMapping = codeMapping;
}
private <T> boolean add(Object2IntMap<T> map, T item) {
@@ -1071,6 +1083,11 @@
}
@Override
+ public void visit(DexEncodedMethod method) {
+ method.collectMixedSectionItemsWithCodeMapping(this, codeMapping);
+ }
+
+ @Override
public boolean add(DexCode code) {
return add(codes, code);
}
diff --git a/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java b/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
index 1c18107..b2a3e09 100644
--- a/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
+++ b/src/main/java/com/android/tools/r8/dex/JumboStringRewriter.java
@@ -107,7 +107,7 @@
this.factory = factory;
}
- public void rewrite() {
+ public DexCode rewrite() {
// Build maps from everything in the code that uses offsets or direct addresses to reference
// instructions to the actual instruction referenced.
recordTargets();
@@ -133,7 +133,7 @@
// As we have rewritten the code, we now know that its highest string index that is not
// a jumbo-string is firstJumboString (actually the previous string, but we do not have that).
newCode.highestSortingString = firstJumboString;
- method.setCode(newCode);
+ return newCode;
}
private void rewriteInstructionOffsets(List<Instruction> instructions) {
diff --git a/src/main/java/com/android/tools/r8/dex/MethodToCodeObjectMapping.java b/src/main/java/com/android/tools/r8/dex/MethodToCodeObjectMapping.java
new file mode 100644
index 0000000..feeb64b
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/dex/MethodToCodeObjectMapping.java
@@ -0,0 +1,78 @@
+// Copyright (c) 2019, 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.dex;
+
+import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.DexCode;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import java.util.Collection;
+import java.util.Map;
+
+public abstract class MethodToCodeObjectMapping {
+
+ public abstract DexCode getCode(DexEncodedMethod method);
+
+ public abstract void clearCode(DexEncodedMethod method, boolean isSharedSynthetic);
+
+ public abstract boolean verifyCodeObjects(Collection<DexCode> codes);
+
+ public static MethodToCodeObjectMapping fromMethodBacking() {
+ return MethodBacking.INSTANCE;
+ }
+
+ public static MethodToCodeObjectMapping fromMapBacking(Map<DexEncodedMethod, DexCode> map) {
+ return new MapBacking(map);
+ }
+
+ private static class MethodBacking extends MethodToCodeObjectMapping {
+
+ private static final MethodBacking INSTANCE = new MethodBacking();
+
+ @Override
+ public DexCode getCode(DexEncodedMethod method) {
+ Code code = method.getCode();
+ assert code == null || code.isDexCode();
+ return code == null ? null : code.asDexCode();
+ }
+
+ @Override
+ public void clearCode(DexEncodedMethod method, boolean isSharedSynthetic) {
+ // When using methods directly any shared class needs to maintain its methods as read-only.
+ if (!isSharedSynthetic) {
+ method.removeCode();
+ }
+ }
+
+ @Override
+ public boolean verifyCodeObjects(Collection<DexCode> codes) {
+ return true;
+ }
+ }
+
+ private static class MapBacking extends MethodToCodeObjectMapping {
+
+ private final Map<DexEncodedMethod, DexCode> codes;
+
+ public MapBacking(Map<DexEncodedMethod, DexCode> codes) {
+ this.codes = codes;
+ }
+
+ @Override
+ public DexCode getCode(DexEncodedMethod method) {
+ return codes.get(method);
+ }
+
+ @Override
+ public void clearCode(DexEncodedMethod method, boolean isSharedSynthetic) {
+ // We can safely clear the thread local pointer to even shared methods.
+ codes.put(method, null);
+ }
+
+ @Override
+ public boolean verifyCodeObjects(Collection<DexCode> codes) {
+ assert this.codes.values().containsAll(codes);
+ return true;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java b/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java
index dee12fc..2cedf5c 100644
--- a/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java
+++ b/src/main/java/com/android/tools/r8/dex/MixedSectionCollection.java
@@ -9,6 +9,7 @@
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexEncodedArray;
+import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexTypeList;
@@ -53,6 +54,16 @@
public abstract boolean add(DexAnnotationSet dexAnnotationSet);
/**
+ * Recurse on the given encoded method to add items to the collection.
+ *
+ * <p>Allows overriding the behavior when dex-file writing.
+ */
+ public void visit(DexEncodedMethod dexEncodedMethod) {
+ dexEncodedMethod.collectMixedSectionItemsWithCodeMapping(
+ this, MethodToCodeObjectMapping.fromMethodBacking());
+ }
+
+ /**
* Adds the given code item to the collection.
*
* Does not add any dependencies.
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index a01f840..1754ad9 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -110,7 +110,7 @@
@Override
public DexEncodedMethod definitionFor(DexMethod method) {
- DexType holderType = method.getHolder();
+ DexType holderType = method.holder;
DexEncodedMethod cached = (DexEncodedMethod) getDefinitions(holderType).get(method);
if (cached != null && cached.isObsolete()) {
definitions.remove(holderType);
@@ -121,7 +121,7 @@
@Override
public DexEncodedField definitionFor(DexField field) {
- return (DexEncodedField) getDefinitions(field.getHolder()).get(field);
+ return (DexEncodedField) getDefinitions(field.holder).get(field);
}
private Map<Descriptor<?,?>, KeyedDexItem<?>> getDefinitions(DexType type) {
@@ -441,7 +441,7 @@
* #resolveFieldOn}.
*/
public DexEncodedField resolveField(DexField field) {
- return resolveFieldOn(field.clazz, field);
+ return resolveFieldOn(field.holder, field);
}
/**
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index eee4acd..6448896 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -108,70 +108,8 @@
}
public AppView<AppInfoWithLiveness> withLiveness() {
- return new AppViewWithLiveness();
- }
-
- private class AppViewWithLiveness extends AppView<AppInfoWithLiveness> {
-
- private AppViewWithLiveness() {
- super(null, null, null);
- }
-
- @Override
- public AppInfoWithLiveness appInfo() {
- return AppView.this.appInfo().withLiveness();
- }
-
- @Override
- public void setAppInfo(AppInfoWithLiveness appInfoWithLiveness) {
- @SuppressWarnings("unchecked")
- T appInfo = (T) appInfoWithLiveness;
- AppView.this.setAppInfo(appInfo);
- }
-
- @Override
- public AppServices appServices() {
- return AppView.this.appServices();
- }
-
- @Override
- public void setAppServices(AppServices appServices) {
- AppView.this.setAppServices(appServices);
- }
-
- @Override
- public DexItemFactory dexItemFactory() {
- return AppView.this.dexItemFactory();
- }
-
- @Override
- public boolean enableWholeProgramOptimizations() {
- return AppView.this.enableWholeProgramOptimizations();
- }
-
- @Override
- public GraphLense graphLense() {
- return AppView.this.graphLense();
- }
-
- @Override
- public void setGraphLense(GraphLense graphLense) {
- AppView.this.setGraphLense(graphLense);
- }
-
- @Override
- public InternalOptions options() {
- return AppView.this.options();
- }
-
- @Override
- public VerticallyMergedClasses verticallyMergedClasses() {
- return AppView.this.verticallyMergedClasses();
- }
-
- @Override
- public AppView<AppInfoWithLiveness> withLiveness() {
- return this;
- }
+ @SuppressWarnings("unchecked")
+ AppView<AppInfoWithLiveness> appViewWithLiveness = (AppView<AppInfoWithLiveness>) this;
+ return appViewWithLiveness;
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/Descriptor.java b/src/main/java/com/android/tools/r8/graph/Descriptor.java
index 7691bfa..09bef34 100644
--- a/src/main/java/com/android/tools/r8/graph/Descriptor.java
+++ b/src/main/java/com/android/tools/r8/graph/Descriptor.java
@@ -8,8 +8,6 @@
public abstract boolean match(T entry);
- public abstract DexType getHolder();
-
@Override
public boolean isDescriptor() {
return true;
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
index 1ef2f68..1f2d9f1 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationDirectory.java
@@ -8,7 +8,6 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.OrderedMergingIterator;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
@@ -38,11 +37,10 @@
parameterAnnotations.add(method);
}
}
- assert isSorted(Arrays.asList(clazz.staticFields()));
- assert isSorted(Arrays.asList(clazz.instanceFields()));
+ assert isSorted(clazz.staticFields());
+ assert isSorted(clazz.instanceFields());
OrderedMergingIterator<DexEncodedField, DexField> fields =
- new OrderedMergingIterator<>(
- Arrays.asList(clazz.staticFields()), Arrays.asList(clazz.instanceFields()));
+ new OrderedMergingIterator<>(clazz.staticFields(), clazz.instanceFields());
fieldAnnotations = new ArrayList<>();
while (fields.hasNext()) {
DexEncodedField field = fields.next();
@@ -68,10 +66,9 @@
return fieldAnnotations;
}
-
/**
- * DexAnnotationDirectory of a class can be canonicalized only if a clazz has annotations and
- * does not contains annotations for his fields, methods or parameters. Indeed, if a field, method
+ * DexAnnotationDirectory of a class can be canonicalized only if a class has annotations and
+ * does not contains annotations for its fields, methods or parameters. Indeed, if a field, method
* or parameter has annotations in this case, the DexAnnotationDirectory can not be shared since
* it will contains information about field, method and parameters that are only related to only
* one class.
diff --git a/src/main/java/com/android/tools/r8/graph/DexCallSite.java b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
index a9f1ea4..382f4bb 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCallSite.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCallSite.java
@@ -205,7 +205,7 @@
}
private void write(DexField field) throws IOException {
- write(field.clazz);
+ write(field.holder);
write(field.type);
write(field.name);
}
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 f303c74..0b104f5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -23,8 +23,11 @@
public abstract class DexClass extends DexDefinition {
- public interface MethodSetter {
+ public interface FieldSetter {
+ void setField(int index, DexEncodedField field);
+ }
+ public interface MethodSetter {
void setMethod(int index, DexEncodedMethod method);
}
@@ -171,8 +174,8 @@
assert verifyNoDuplicateMethods();
}
- public void setDirectMethods(DexEncodedMethod[] values) {
- directMethods = MoreObjects.firstNonNull(values, NO_METHODS);
+ public void setDirectMethods(DexEncodedMethod[] methods) {
+ directMethods = MoreObjects.firstNonNull(methods, NO_METHODS);
assert verifyCorrectnessOfMethodHolders(directMethods());
assert verifyNoDuplicateMethods();
}
@@ -221,8 +224,8 @@
assert verifyNoDuplicateMethods();
}
- public void setVirtualMethods(DexEncodedMethod[] values) {
- virtualMethods = MoreObjects.firstNonNull(values, NO_METHODS);
+ public void setVirtualMethods(DexEncodedMethod[] methods) {
+ virtualMethods = MoreObjects.firstNonNull(methods, NO_METHODS);
assert verifyCorrectnessOfMethodHolders(virtualMethods());
assert verifyNoDuplicateMethods();
}
@@ -340,12 +343,53 @@
}
}
- public DexEncodedField[] staticFields() {
- return staticFields;
+ public List<DexEncodedField> staticFields() {
+ assert staticFields != null;
+ if (InternalOptions.assertionsEnabled()) {
+ return Collections.unmodifiableList(Arrays.asList(staticFields));
+ }
+ return Arrays.asList(staticFields);
}
- public void setStaticFields(DexEncodedField[] values) {
- staticFields = MoreObjects.firstNonNull(values, NO_FIELDS);
+ public void appendStaticField(DexEncodedField field) {
+ DexEncodedField[] newFields = new DexEncodedField[staticFields.length + 1];
+ System.arraycopy(staticFields, 0, newFields, 0, staticFields.length);
+ newFields[staticFields.length] = field;
+ staticFields = newFields;
+ assert verifyCorrectnessOfFieldHolder(field);
+ assert verifyNoDuplicateFields();
+ }
+
+ public void appendStaticFields(Collection<DexEncodedField> fields) {
+ DexEncodedField[] newFields = new DexEncodedField[staticFields.length + fields.size()];
+ System.arraycopy(staticFields, 0, newFields, 0, staticFields.length);
+ int i = staticFields.length;
+ for (DexEncodedField field : fields) {
+ newFields[i] = field;
+ i++;
+ }
+ staticFields = newFields;
+ assert verifyCorrectnessOfFieldHolders(fields);
+ assert verifyNoDuplicateFields();
+ }
+
+ public void removeStaticField(int index) {
+ DexEncodedField[] newFields = new DexEncodedField[staticFields.length - 1];
+ System.arraycopy(staticFields, 0, newFields, 0, index);
+ System.arraycopy(staticFields, index + 1, newFields, index, staticFields.length - index - 1);
+ staticFields = newFields;
+ }
+
+ public void setStaticField(int index, DexEncodedField field) {
+ staticFields[index] = field;
+ assert verifyCorrectnessOfFieldHolder(field);
+ assert verifyNoDuplicateFields();
+ }
+
+ public void setStaticFields(DexEncodedField[] fields) {
+ staticFields = MoreObjects.firstNonNull(fields, NO_FIELDS);
+ assert verifyCorrectnessOfFieldHolders(staticFields());
+ assert verifyNoDuplicateFields();
}
public boolean definesStaticField(DexField field) {
@@ -357,12 +401,80 @@
return false;
}
- public DexEncodedField[] instanceFields() {
- return instanceFields;
+ public List<DexEncodedField> instanceFields() {
+ assert instanceFields != null;
+ if (InternalOptions.assertionsEnabled()) {
+ return Collections.unmodifiableList(Arrays.asList(instanceFields));
+ }
+ return Arrays.asList(instanceFields);
}
- public void setInstanceFields(DexEncodedField[] values) {
- instanceFields = MoreObjects.firstNonNull(values, NO_FIELDS);
+ public void appendInstanceField(DexEncodedField field) {
+ DexEncodedField[] newFields = new DexEncodedField[instanceFields.length + 1];
+ System.arraycopy(instanceFields, 0, newFields, 0, instanceFields.length);
+ newFields[instanceFields.length] = field;
+ instanceFields = newFields;
+ assert verifyCorrectnessOfFieldHolder(field);
+ assert verifyNoDuplicateFields();
+ }
+
+ public void appendInstanceFields(Collection<DexEncodedField> fields) {
+ DexEncodedField[] newFields = new DexEncodedField[instanceFields.length + fields.size()];
+ System.arraycopy(instanceFields, 0, newFields, 0, instanceFields.length);
+ int i = instanceFields.length;
+ for (DexEncodedField field : fields) {
+ newFields[i] = field;
+ i++;
+ }
+ instanceFields = newFields;
+ assert verifyCorrectnessOfFieldHolders(fields);
+ assert verifyNoDuplicateFields();
+ }
+
+ public void removeInstanceField(int index) {
+ DexEncodedField[] newFields = new DexEncodedField[instanceFields.length - 1];
+ System.arraycopy(instanceFields, 0, newFields, 0, index);
+ System.arraycopy(
+ instanceFields, index + 1, newFields, index, instanceFields.length - index - 1);
+ instanceFields = newFields;
+ }
+
+ public void setInstanceField(int index, DexEncodedField field) {
+ instanceFields[index] = field;
+ assert verifyCorrectnessOfFieldHolder(field);
+ assert verifyNoDuplicateFields();
+ }
+
+ public void setInstanceFields(DexEncodedField[] fields) {
+ instanceFields = MoreObjects.firstNonNull(fields, NO_FIELDS);
+ assert verifyCorrectnessOfFieldHolders(instanceFields());
+ assert verifyNoDuplicateFields();
+ }
+
+ private boolean verifyCorrectnessOfFieldHolder(DexEncodedField field) {
+ assert field.field.holder == type
+ : "Expected field `"
+ + field.field.toSourceString()
+ + "` to have holder `"
+ + type.toSourceString()
+ + "`";
+ return true;
+ }
+
+ private boolean verifyCorrectnessOfFieldHolders(Iterable<DexEncodedField> fields) {
+ for (DexEncodedField field : fields) {
+ assert verifyCorrectnessOfFieldHolder(field);
+ }
+ return true;
+ }
+
+ private boolean verifyNoDuplicateFields() {
+ Set<DexField> unique = Sets.newIdentityHashSet();
+ for (DexEncodedField field : fields()) {
+ boolean changed = unique.add(field.field);
+ assert changed : "Duplicate field `" + field.field.toSourceString() + "`";
+ }
+ return true;
}
public DexEncodedField[] allFieldsSorted() {
@@ -380,14 +492,14 @@
* Find static field in this class matching field
*/
public DexEncodedField lookupStaticField(DexField field) {
- return lookupTarget(staticFields(), field);
+ return lookupTarget(staticFields, field);
}
/**
* Find instance field in this class matching field.
*/
public DexEncodedField lookupInstanceField(DexField field) {
- return lookupTarget(instanceFields(), field);
+ return lookupTarget(instanceFields, field);
}
/**
@@ -598,7 +710,7 @@
}
public boolean defaultValuesForStaticFieldsMayTriggerAllocation() {
- return Arrays.stream(staticFields())
+ return staticFields().stream()
.anyMatch(field -> field.getStaticValue().mayHaveSideEffects());
}
@@ -669,6 +781,8 @@
public boolean isValid() {
assert !isInterface()
|| Arrays.stream(virtualMethods).noneMatch(method -> method.accessFlags.isFinal());
+ assert verifyCorrectnessOfFieldHolders(fields());
+ assert verifyNoDuplicateFields();
assert verifyCorrectnessOfMethodHolders(methods());
assert verifyNoDuplicateMethods();
return true;
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
index eca2384..49611c6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEntryBuilder.java
@@ -73,7 +73,7 @@
int argumentRegister = code.registerSize - code.incomingRegisterSize;
if (!method.accessFlags.isStatic()) {
DexString name = factory.thisName;
- DexType type = method.method.getHolder();
+ DexType type = method.method.holder;
startArgument(argumentRegister, name, type);
argumentRegister += ValueType.fromDexType(type).requiredRegisters();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 58fe234..9c7b10a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -31,8 +31,8 @@
}
public boolean isProgramField(AppInfo appInfo) {
- if (field.clazz.isClassType()) {
- DexClass clazz = appInfo.definitionFor(field.clazz);
+ if (field.holder.isClassType()) {
+ DexClass clazz = appInfo.definitionFor(field.holder);
return clazz != null && clazz.isProgramClass();
}
return false;
@@ -130,7 +130,7 @@
return null;
}
if (accessFlags.isStatic()) {
- DexClass clazz = appInfo.definitionFor(field.clazz);
+ DexClass clazz = appInfo.definitionFor(field.holder);
assert clazz != null : "Class for the field must be present";
return getStaticValue().asConstInstruction(clazz.hasClassInitializer(), dest, options);
}
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 9fa16f1..057090e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -23,6 +23,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.JumboStringRewriter;
+import com.android.tools.r8.dex.MethodToCodeObjectMapping;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.errors.Unreachable;
@@ -255,7 +256,7 @@
public boolean isInliningCandidate(
DexEncodedMethod container, Reason inliningReason, AppInfoWithSubtyping appInfo) {
checkIfObsolete();
- return isInliningCandidate(container.method.getHolder(), inliningReason, appInfo);
+ return isInliningCandidate(container.method.holder, inliningReason, appInfo);
}
public boolean isInliningCandidate(
@@ -279,11 +280,11 @@
case PROCESSED_INLINING_CANDIDATE_ANY:
return true;
case PROCESSED_INLINING_CANDIDATE_SUBCLASS:
- return containerType.isSubtypeOf(method.getHolder(), appInfo);
+ return containerType.isSubtypeOf(method.holder, appInfo);
case PROCESSED_INLINING_CANDIDATE_SAME_PACKAGE:
- return containerType.isSamePackage(method.getHolder());
+ return containerType.isSamePackage(method.holder);
case PROCESSED_INLINING_CANDIDATE_SAME_CLASS:
- return containerType == method.getHolder();
+ return containerType == method.holder;
default:
return false;
}
@@ -366,6 +367,12 @@
@Override
void collectMixedSectionItems(MixedSectionCollection mixedItems) {
+ mixedItems.visit(this);
+ }
+
+ public void collectMixedSectionItemsWithCodeMapping(
+ MixedSectionCollection mixedItems, MethodToCodeObjectMapping mapping) {
+ DexCode code = mapping.getCode(this);
if (code != null) {
code.collectMixedSectionItems(mixedItems);
}
@@ -678,19 +685,13 @@
return method;
}
- /**
- * Rewrites the code in this method to have JumboString bytecode if required by mapping.
- * <p>
- * Synchronized such that it can be called concurrently for different mappings. As a side-effect,
- * this will also update the highestSortingString to the index of the strings up to which the code
- * was rewritten to avoid rewriting again unless needed.
- */
- public synchronized void rewriteCodeWithJumboStrings(
- ObjectToOffsetMapping mapping, DexApplication application, boolean force) {
+ /** Rewrites the code in this method to have JumboString bytecode if required by mapping. */
+ public DexCode rewriteCodeWithJumboStrings(
+ ObjectToOffsetMapping mapping, DexItemFactory factory, boolean force) {
checkIfObsolete();
assert code == null || code.isDexCode();
if (code == null) {
- return;
+ return null;
}
DexCode code = this.code.asDexCode();
DexString firstJumboString = null;
@@ -706,10 +707,10 @@
}
}
if (firstJumboString != null) {
- JumboStringRewriter rewriter =
- new JumboStringRewriter(this, firstJumboString, application.dexItemFactory);
- rewriter.rewrite();
+ JumboStringRewriter rewriter = new JumboStringRewriter(this, firstJumboString, factory);
+ return rewriter.rewrite();
}
+ return code;
}
public String codeToString() {
diff --git a/src/main/java/com/android/tools/r8/graph/DexField.java b/src/main/java/com/android/tools/r8/graph/DexField.java
index 550a91f..1f106b7 100644
--- a/src/main/java/com/android/tools/r8/graph/DexField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -10,12 +10,12 @@
public class DexField extends Descriptor<DexEncodedField, DexField> implements
PresortedComparable<DexField> {
- public final DexType clazz;
+ public final DexType holder;
public final DexType type;
public final DexString name;
- DexField(DexType clazz, DexType type, DexString name, boolean skipNameValidationForTesting) {
- this.clazz = clazz;
+ DexField(DexType holder, DexType type, DexString name, boolean skipNameValidationForTesting) {
+ this.holder = holder;
this.type = type;
this.name = name;
if (!skipNameValidationForTesting && !name.isValidFieldName()) {
@@ -26,7 +26,7 @@
@Override
public int computeHashCode() {
- return clazz.hashCode()
+ return holder.hashCode()
+ type.hashCode() * 7
+ name.hashCode() * 31;
}
@@ -35,7 +35,7 @@
public boolean computeEquals(Object other) {
if (other instanceof DexField) {
DexField o = (DexField) other;
- return clazz.equals(o.clazz)
+ return holder.equals(o.holder)
&& type.equals(o.type)
&& name.equals(o.name);
}
@@ -44,14 +44,14 @@
@Override
public String toString() {
- return "Field " + type + " " + clazz + "." + name;
+ return "Field " + type + " " + holder + "." + name;
}
@Override
public void collectIndexedItems(IndexedItemCollection indexedItems,
DexMethod method, int instructionOffset) {
if (indexedItems.addField(this)) {
- clazz.collectIndexedItems(indexedItems, method, instructionOffset);
+ holder.collectIndexedItems(indexedItems, method, instructionOffset);
type.collectIndexedItems(indexedItems, method, instructionOffset);
indexedItems.getRenamedName(this).collectIndexedItems(
indexedItems, method, instructionOffset);
@@ -80,7 +80,7 @@
@Override
public int slowCompareTo(DexField other) {
- int result = clazz.slowCompareTo(other.clazz);
+ int result = holder.slowCompareTo(other.holder);
if (result != 0) {
return result;
}
@@ -93,7 +93,7 @@
@Override
public int slowCompareTo(DexField other, NamingLens namingLens) {
- int result = clazz.slowCompareTo(other.clazz, namingLens);
+ int result = holder.slowCompareTo(other.holder, namingLens);
if (result != 0) {
return result;
}
@@ -106,7 +106,7 @@
@Override
public int layeredCompareTo(DexField other, NamingLens namingLens) {
- int result = clazz.compareTo(other.clazz);
+ int result = holder.compareTo(other.holder);
if (result != 0) {
return result;
}
@@ -122,22 +122,17 @@
return entry.field.name == name && entry.field.type == type;
}
- @Override
- public DexType getHolder() {
- return clazz;
- }
-
public String qualifiedName() {
- return clazz + "." + name;
+ return holder + "." + name;
}
@Override
public String toSmaliString() {
- return clazz.toSmaliString() + "->" + name + ":" + type.toSmaliString();
+ return holder.toSmaliString() + "->" + name + ":" + type.toSmaliString();
}
@Override
public String toSourceString() {
- return type.toSourceString() + " " + clazz.toSourceString() + "." + name.toSourceString();
+ return type.toSourceString() + " " + holder.toSourceString() + "." + name.toSourceString();
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index bd86c12..964735a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -152,11 +152,6 @@
return entry.method.name == name && entry.method.proto == proto;
}
- @Override
- public DexType getHolder() {
- return holder;
- }
-
public String qualifiedName() {
return holder + "." + name;
}
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 3af0a41..8d7b98a 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethodHandle.java
@@ -374,10 +374,10 @@
} else {
assert isFieldHandle();
DexField field = asField();
- owner = lens.lookupInternalName(field.clazz);
+ owner = lens.lookupInternalName(field.holder);
name = lens.lookupName(field).toString();
desc = lens.lookupDescriptor(field.type).toString();
- itf = field.clazz.isInterface();
+ itf = field.holder.isInterface();
}
return new Handle(getAsmTag(), owner, name, desc, itf);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index 57b08fb..4312bfd 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -225,7 +225,7 @@
}
public boolean hasMethodsOrFields() {
- int numberOfFields = staticFields().length + instanceFields().length;
+ int numberOfFields = staticFields().size() + instanceFields().size();
int numberOfMethods = directMethods().size() + virtualMethods().size();
return numberOfFields + numberOfMethods > 0;
}
diff --git a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
index 57bc3c4..0fe8c04 100644
--- a/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
+++ b/src/main/java/com/android/tools/r8/graph/EnclosingMethodAttribute.java
@@ -35,7 +35,7 @@
public void write(ClassWriter writer, NamingLens lens) {
if (enclosingMethod != null) {
writer.visitOuterClass(
- lens.lookupInternalName(enclosingMethod.getHolder()),
+ lens.lookupInternalName(enclosingMethod.holder),
lens.lookupName(enclosingMethod).toString(),
enclosingMethod.proto.toDescriptorString(lens));
} else {
diff --git a/src/main/java/com/android/tools/r8/graph/JarCode.java b/src/main/java/com/android/tools/r8/graph/JarCode.java
index 732f35b..33d145f 100644
--- a/src/main/java/com/android/tools/r8/graph/JarCode.java
+++ b/src/main/java/com/android/tools/r8/graph/JarCode.java
@@ -192,7 +192,7 @@
assert node.localVariables.isEmpty() || keepLocals(encodedMethod, appView.options());
JarSourceCode source =
new JarSourceCode(
- method.getHolder(),
+ method.holder,
node,
application,
appView.graphLense().getOriginalMethodSignature(encodedMethod.method),
@@ -205,7 +205,7 @@
public void registerCodeReferences(UseRegistry registry) {
triggerDelayedParsingIfNeccessary();
node.instructions.accept(
- new JarRegisterEffectsVisitor(method.getHolder(), registry, application));
+ new JarRegisterEffectsVisitor(method.holder, registry, application));
for (TryCatchBlockNode tryCatchBlockNode : node.tryCatchBlocks) {
// Exception type can be null for "catch all" used for try/finally.
if (tryCatchBlockNode.type != null) {
@@ -223,7 +223,7 @@
public ConstraintWithTarget computeInliningConstraint(
DexEncodedMethod encodedMethod,
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<AppInfoWithLiveness> appView,
GraphLense graphLense,
DexType invocationContext) {
InliningConstraintVisitor visitor =
diff --git a/src/main/java/com/android/tools/r8/graph/UseRegistry.java b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
index ccf790b..1d0b4fb 100644
--- a/src/main/java/com/android/tools/r8/graph/UseRegistry.java
+++ b/src/main/java/com/android/tools/r8/graph/UseRegistry.java
@@ -78,7 +78,7 @@
break;
case INVOKE_CONSTRUCTOR:
DexMethod method = methodHandle.asMethod();
- registerNewInstance(method.getHolder());
+ registerNewInstance(method.holder);
registerInvokeDirect(method);
break;
case INVOKE_INTERFACE:
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
index 120a099..757dcac 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/ClassInitializationAnalysis.java
@@ -59,7 +59,7 @@
}
};
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final IRCode code;
private final DexItemFactory dexItemFactory;
@@ -72,7 +72,7 @@
this.dexItemFactory = null;
}
- public ClassInitializationAnalysis(AppView<? extends AppInfoWithLiveness> appView, IRCode code) {
+ public ClassInitializationAnalysis(AppView<AppInfoWithLiveness> appView, IRCode code) {
this.appView = appView;
this.code = code;
this.dexItemFactory = appView.dexItemFactory();
@@ -276,7 +276,7 @@
return false;
}
}
- return isTypeInitializedBy(type, instruction.getField().clazz, appView, mode);
+ return isTypeInitializedBy(type, instruction.getField().holder, appView, mode);
}
public static boolean forInvokeDirect(
@@ -407,7 +407,7 @@
// Class initialization may fail with ExceptionInInitializerError.
return false;
}
- return isTypeInitializedBy(type, instruction.getField().clazz, appView, mode);
+ return isTypeInitializedBy(type, instruction.getField().holder, appView, mode);
}
private static boolean isTypeInitializedBy(
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
index e5ea8b7..719f954 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/type/TypeAnalysis.java
@@ -171,7 +171,7 @@
public static DexType getRefinedReceiverType(
DexDefinitionSupplier definitions, InvokeMethodWithReceiver invoke) {
- DexType receiverType = invoke.getInvokedMethod().getHolder();
+ DexType receiverType = invoke.getInvokedMethod().holder;
TypeLatticeElement lattice = invoke.getReceiver().getTypeLattice();
if (lattice.isClassType()) {
DexType refinedType = lattice.asClassTypeLatticeElement().getClassType();
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
index 3634edf..c78cd20 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceGet.java
@@ -118,8 +118,8 @@
}
if (!isMemberVisibleFromOriginalContext(
appInfo,
- code.method.method.getHolder(),
- resolvedField.field.clazz,
+ code.method.method.holder,
+ resolvedField.field.holder,
resolvedField.accessFlags)) {
return false;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
index 6358853..15623e0 100644
--- a/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
+++ b/src/main/java/com/android/tools/r8/ir/code/StaticGet.java
@@ -111,13 +111,13 @@
}
if (!isMemberVisibleFromOriginalContext(
appInfo,
- code.method.method.getHolder(),
- resolvedField.field.clazz,
+ code.method.method.holder,
+ resolvedField.field.holder,
resolvedField.accessFlags)) {
return false;
}
DexType context = code.method.method.holder;
- return !getField().clazz.classInitializationMayHaveSideEffects(
+ return !getField().holder.classInitializationMayHaveSideEffects(
appInfo,
// Types that are a super type of `context` are guaranteed to be initialized already.
type -> context.isSubtypeOf(type, appInfo));
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 ab1e319..f8465d0 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
@@ -150,7 +150,7 @@
public static CallGraph build(
DexApplication application,
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<AppInfoWithLiveness> appView,
InternalOptions options,
Timing timing) {
CallGraph graph = new CallGraph(options);
@@ -488,7 +488,7 @@
private final Node caller;
private final CallGraph graph;
- InvokeExtractor(AppView<? extends AppInfoWithLiveness> appView, Node caller, CallGraph graph) {
+ InvokeExtractor(AppView<AppInfoWithLiveness> appView, Node caller, CallGraph graph) {
super(appView.dexItemFactory());
this.appInfo = appView.appInfo();
this.graphLense = appView.graphLense();
@@ -518,7 +518,7 @@
private void addPossibleTarget(DexEncodedMethod possibleTarget) {
DexClass possibleTargetClass =
- appInfo.definitionFor(possibleTarget.method.getHolder());
+ appInfo.definitionFor(possibleTarget.method.holder);
if (possibleTargetClass != null && !possibleTargetClass.isLibraryClass()) {
addTarget(possibleTarget);
}
@@ -541,7 +541,7 @@
DexEncodedMethod definition = appInfo.lookup(type, method, source.method.holder);
if (definition != null) {
assert !source.accessFlags.isBridge() || definition != caller.method;
- DexClass clazz = appInfo.definitionFor(definition.method.getHolder());
+ DexClass clazz = appInfo.definitionFor(definition.method.holder);
assert clazz != null;
if (clazz.isProgramClass()) {
// For static invokes, the class could be initialized.
@@ -566,10 +566,10 @@
private void processFieldAccess(DexField field) {
// Any field access implicitly calls the class initializer.
- if (field.clazz.isClassType()) {
+ if (field.holder.isClassType()) {
DexEncodedField encodedField = appInfo.resolveField(field);
if (encodedField != null && encodedField.isStatic()) {
- addClassInitializerTarget(field.getHolder());
+ addClassInitializerTarget(field.holder);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
index 0d7f6e1..a9ecdf7 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/IRBuilder.java
@@ -858,7 +858,7 @@
boolean receiverCouldBeNull = context != null && context != method;
Nullability nullability = receiverCouldBeNull ? maybeNull() : definitelyNotNull();
TypeLatticeElement receiver =
- TypeLatticeElement.fromDexType(method.method.getHolder(), nullability, appView);
+ TypeLatticeElement.fromDexType(method.method.holder, nullability, appView);
Value value = writeRegister(register, receiver, ThrowingInfo.NO_THROW, local);
addInstruction(new Argument(value));
value.markAsThis();
@@ -1361,7 +1361,7 @@
"MethodHandle.invoke and MethodHandle.invokeExact",
null /* sourceString */);
} else if (!appView.options().canUseInvokePolymorphicOnVarHandle()
- && ((DexMethod) item).getHolder() == appView.dexItemFactory().varHandleType) {
+ && ((DexMethod) item).holder == appView.dexItemFactory().varHandleType) {
throw new ApiLevelException(
AndroidApiLevel.P,
"Call to polymorphic signature of VarHandle",
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 85d9a2f..a66e958 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
@@ -188,9 +188,14 @@
? new CovariantReturnTypeAnnotationTransformer(this, appView.dexItemFactory())
: null;
this.stringOptimizer = new StringOptimizer(appView);
+ this.nonNullTracker =
+ options.enableNonNullTracking
+ ? new NonNullTracker(
+ appView, libraryMethodsReturningNonNull(appView.dexItemFactory()))
+ : null;
if (appView.enableWholeProgramOptimizations()) {
assert appView.appInfo().hasLiveness();
- AppView<? extends AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
AppInfoWithLiveness appInfoWithLiveness = appViewWithLiveness.appInfo();
assert rootSet != null;
this.classInliner =
@@ -199,9 +204,6 @@
: null;
this.classStaticizer =
options.enableClassStaticizer ? new ClassStaticizer(appViewWithLiveness, this) : null;
- this.nonNullTracker =
- new NonNullTracker(
- appViewWithLiveness, libraryMethodsReturningNonNull(appView.dexItemFactory()));
this.inliner = new Inliner(appViewWithLiveness, mainDexClasses);
this.outliner = new Outliner(appViewWithLiveness, this);
this.memberValuePropagation =
@@ -222,7 +224,6 @@
} else {
this.classInliner = null;
this.classStaticizer = null;
- this.nonNullTracker = null;
this.inliner = null;
this.outliner = null;
this.memberValuePropagation = null;
@@ -946,7 +947,7 @@
if (devirtualizer != null) {
assert code.verifyTypes(appView);
- devirtualizer.devirtualizeInvokeInterface(code, method.method.getHolder());
+ devirtualizer.devirtualizeInvokeInterface(code, method.method.holder);
}
if (uninstantiatedTypeOptimization != null) {
uninstantiatedTypeOptimization.rewrite(method, code);
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index e8cf039..7b58034 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -145,7 +145,7 @@
} else if (current.isInvokeMethod()) {
InvokeMethod invoke = current.asInvokeMethod();
DexMethod invokedMethod = invoke.getInvokedMethod();
- DexType invokedHolder = invokedMethod.getHolder();
+ DexType invokedHolder = invokedMethod.holder;
if (invokedHolder.isArrayType()) {
DexType baseType = invokedHolder.toBaseType(appInfo.dexItemFactory);
DexType mappedBaseType = graphLense.lookupType(baseType);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index fb5fac8..3976ad7 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -508,7 +508,7 @@
}
private Origin getMethodOrigin(DexMethod method) {
- DexType holder = method.getHolder();
+ DexType holder = method.holder;
if (isCompanionClassType(holder)) {
holder = getInterfaceClassType(holder);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ArgumentRemovalUtils.java b/src/main/java/com/android/tools/r8/ir/optimize/ArgumentRemovalUtils.java
index 7c6c985..a92d536 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ArgumentRemovalUtils.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ArgumentRemovalUtils.java
@@ -12,8 +12,7 @@
// Returns true if this method is pinned from the perspective of optimizations that attempt to
// remove method arguments.
- public static boolean isPinned(
- DexEncodedMethod method, AppView<? extends AppInfoWithLiveness> appView) {
+ public static boolean isPinned(DexEncodedMethod method, AppView<AppInfoWithLiveness> appView) {
return appView.appInfo().isPinned(method.method)
|| appView.appInfo().bootstrapMethods.contains(method.method)
|| appView.appInfo().brokenSuperInvokes.contains(method.method)
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
index ff903f3..36f54a6 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ClassInitializerDefaultsOptimization.java
@@ -204,7 +204,7 @@
// that the field is no longer written.
if (appView.enableWholeProgramOptimizations() && converter.isInWave()) {
if (appView.appInfo().hasLiveness()) {
- AppView<? extends AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
AppInfoWithLiveness appInfoWithLiveness = appViewWithLiveness.appInfo();
// First collect all the candidate fields that are *potentially* no longer being written to.
@@ -330,7 +330,7 @@
if (instruction.isStaticGet()) {
StaticGet get = instruction.asStaticGet();
DexEncodedField field = appView.appInfo().resolveField(get.getField());
- if (field != null && field.field.clazz == clazz.type) {
+ if (field != null && field.field.holder == clazz.type) {
isReadBefore.add(field.field);
} else if (instruction.instructionMayHaveSideEffects(appView, clazz.type)) {
// Reading another field is only OK if the read does not have side-effects.
@@ -338,7 +338,7 @@
}
} else if (instruction.isStaticPut()) {
StaticPut put = instruction.asStaticPut();
- if (put.getField().clazz != clazz.type) {
+ if (put.getField().holder != clazz.type) {
// Can cause clinit on another class which can read uninitialized static fields
// of this class.
return finalFieldPut.values();
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 0015e17..240ad73 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
@@ -1078,7 +1078,7 @@
}
}
DexField field = insn.asFieldInstruction().getField();
- if (field.clazz == clazz.type && clazz.lookupInstanceField(field) != null) {
+ if (field.holder == clazz.type && clazz.lookupInstanceField(field) != null) {
// Require only accessing instance fields of the *current* class.
continue;
}
@@ -1440,7 +1440,7 @@
Wrapper<DexMethod> methodWrap = wrapper.wrap(invokedMethod);
if (methodWrap.equals(throwParamIsNullException)
|| (methodWrap.equals(checkParameterIsNotNull) && instr.inValues().get(0).equals(value))) {
- if (invokedMethod.getHolder().getPackageDescriptor().startsWith(Kotlin.NAME)) {
+ if (invokedMethod.holder.getPackageDescriptor().startsWith(Kotlin.NAME)) {
return true;
}
}
@@ -1592,7 +1592,7 @@
return invoke.getInvokedMethod().proto.parameters.values[argumentIndex];
}
if (argumentIndex == 0) {
- return invoke.getInvokedMethod().getHolder();
+ return invoke.getInvokedMethod().holder;
}
return invoke.getInvokedMethod().proto.parameters.values[argumentIndex - 1];
}
@@ -1638,7 +1638,7 @@
}
} else if (appInfoWithLiveness != null) {
DexEncodedMethod target =
- invoke.lookupSingleTarget(appInfoWithLiveness, code.method.method.getHolder());
+ invoke.lookupSingleTarget(appInfoWithLiveness, code.method.method.holder);
if (target != null) {
DexMethod invokedMethod = target.method;
// Check if the invoked method is known to return one of its arguments.
@@ -1956,7 +1956,7 @@
}
ConstraintWithTarget classVisibility =
ConstraintWithTarget.deriveConstraint(
- context.method.getHolder(), baseType, clazz.accessFlags, appInfo);
+ context.method.holder, baseType, clazz.accessFlags, appInfo);
return classVisibility == ConstraintWithTarget.NEVER;
}
@@ -3179,7 +3179,7 @@
}
DexEncodedMethod singleTarget = insn.asInvokeMethod().lookupSingleTarget(
- appInfoWithLiveness, code.method.method.getHolder());
+ appInfoWithLiveness, code.method.method.holder);
if (singleTarget == null || !singleTarget.getOptimizationInfo().neverReturnsNormally()) {
continue;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index 3f1b066..aa90c7f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -33,7 +33,7 @@
public final class DefaultInliningOracle implements InliningOracle, InliningStrategy {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final Inliner inliner;
private final DexEncodedMethod method;
private final IRCode code;
@@ -44,7 +44,7 @@
private int instructionAllowance;
DefaultInliningOracle(
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<AppInfoWithLiveness> appView,
Inliner inliner,
DexEncodedMethod method,
IRCode code,
@@ -75,7 +75,7 @@
invoke.lookupSingleTarget(inliner.appView.appInfo(), invocationContext);
if ((candidate == null)
|| (candidate.getCode() == null)
- || inliner.appView.definitionFor(candidate.method.getHolder()).isLibraryClass()) {
+ || inliner.appView.definitionFor(candidate.method.holder).isLibraryClass()) {
if (info != null) {
info.exclude(invoke, "No inlinee");
}
@@ -196,7 +196,7 @@
return false;
}
- DexClass holder = inliner.appView.definitionFor(candidate.method.getHolder());
+ DexClass holder = inliner.appView.definitionFor(candidate.method.holder);
if (holder.isInterface()) {
// Art978_virtual_interfaceTest correctly expects an IncompatibleClassChangeError exception at
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
index d0f3599..8fc16fe 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Devirtualizer.java
@@ -35,9 +35,9 @@
*/
public class Devirtualizer {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
- public Devirtualizer(AppView<? extends AppInfoWithLiveness> appView) {
+ public Devirtualizer(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
}
@@ -112,7 +112,7 @@
if (target == null) {
continue;
}
- DexType holderType = target.method.getHolder();
+ DexType holderType = target.method.holder;
DexClass holderClass = appView.definitionFor(holderType);
// Make sure we are not landing on another interface, e.g., interface's default method.
if (holderClass == null || holderClass.isInterface()) {
@@ -140,7 +140,7 @@
// CodeRewriter#removeTrivialCheckCastAndInstanceOfInstructions}.
// a <- check-cast A i // Otherwise ART verification error.
// (out <-) invoke-virtual a, ... A#foo
- if (holderType != invoke.getInvokedMethod().getHolder()) {
+ if (holderType != invoke.getInvokedMethod().holder) {
Value receiver = invoke.getReceiver();
TypeLatticeElement receiverTypeLattice = receiver.getTypeLattice();
TypeLatticeElement castTypeLattice =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java
index aa3b405..01ef3ab 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/EnumOrdinalMapCollector.java
@@ -29,11 +29,11 @@
*/
public class EnumOrdinalMapCollector {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final Map<DexType, Reference2IntMap<DexField>> ordinalsMaps = new IdentityHashMap<>();
- public EnumOrdinalMapCollector(AppView<? extends AppInfoWithLiveness> appView) {
+ public EnumOrdinalMapCollector(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
}
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 9a50518..55876af 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
@@ -49,7 +49,7 @@
public class Inliner {
- protected final AppView<? extends AppInfoWithLiveness> appView;
+ protected final AppView<AppInfoWithLiveness> appView;
final MainDexClasses mainDexClasses;
// State for inlining methods which are known to be called twice.
@@ -60,9 +60,7 @@
private final Set<DexMethod> blackList = Sets.newIdentityHashSet();
- public Inliner(
- AppView<? extends AppInfoWithLiveness> appView,
- MainDexClasses mainDexClasses) {
+ public Inliner(AppView<AppInfoWithLiveness> appView, MainDexClasses mainDexClasses) {
this.appView = appView;
this.mainDexClasses = mainDexClasses;
fillInBlackList(appView.appInfo());
@@ -522,7 +520,7 @@
return false;
}
DexField field = instruction.asInstancePut().getField();
- DexEncodedField target = appView.appInfo().lookupInstanceTarget(field.getHolder(), field);
+ DexEncodedField target = appView.appInfo().lookupInstanceTarget(field.holder, field);
if (target != null && target.accessFlags.isFinal()) {
return false;
}
@@ -673,10 +671,10 @@
if (assumedReceiverType == null) {
// In case we don't know exact type of the receiver we use declared
// method holder as a fallback.
- assumedReceiverType = invoke.getInvokedMethod().getHolder();
+ assumedReceiverType = invoke.getInvokedMethod().holder;
}
- if (assumedReceiverType != target.method.getHolder()) {
- return target.method.getHolder();
+ if (assumedReceiverType != target.method.holder) {
+ return target.method.holder;
}
}
return null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
index afb2e0f..efec070 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/InliningConstraints.java
@@ -23,7 +23,7 @@
// Computes the inlining constraint for a given instruction.
public class InliningConstraints {
- private AppView<? extends AppInfoWithLiveness> appView;
+ private AppView<AppInfoWithLiveness> appView;
private boolean allowStaticInterfaceMethodCalls = true;
@@ -39,8 +39,7 @@
// type A to B, to create a temporary view of what the world would look like after class merging.
private GraphLense graphLense;
- public InliningConstraints(
- AppView<? extends AppInfoWithLiveness> appView, GraphLense graphLense) {
+ public InliningConstraints(AppView<AppInfoWithLiveness> appView, GraphLense graphLense) {
assert graphLense.isContextFreeForMethods();
assert appView.graphLense() != graphLense || graphLense.isIdentityLense();
this.appView = appView;
@@ -110,7 +109,7 @@
public ConstraintWithTarget forInstanceGet(DexField field, DexType invocationContext) {
DexField lookup = graphLense.lookupField(field);
return forFieldInstruction(
- lookup, appView.appInfo().lookupInstanceTarget(lookup.clazz, lookup), invocationContext);
+ lookup, appView.appInfo().lookupInstanceTarget(lookup.holder, lookup), invocationContext);
}
public ConstraintWithTarget forInstanceOf(DexType type, DexType invocationContext) {
@@ -120,7 +119,7 @@
public ConstraintWithTarget forInstancePut(DexField field, DexType invocationContext) {
DexField lookup = graphLense.lookupField(field);
return forFieldInstruction(
- lookup, appView.appInfo().lookupInstanceTarget(lookup.clazz, lookup), invocationContext);
+ lookup, appView.appInfo().lookupInstanceTarget(lookup.holder, lookup), invocationContext);
}
public ConstraintWithTarget forInvoke(DexMethod method, Type type, DexType invocationContext) {
@@ -237,13 +236,13 @@
public ConstraintWithTarget forStaticGet(DexField field, DexType invocationContext) {
DexField lookup = graphLense.lookupField(field);
return forFieldInstruction(
- lookup, appView.appInfo().lookupStaticTarget(lookup.clazz, lookup), invocationContext);
+ lookup, appView.appInfo().lookupStaticTarget(lookup.holder, lookup), invocationContext);
}
public ConstraintWithTarget forStaticPut(DexField field, DexType invocationContext) {
DexField lookup = graphLense.lookupField(field);
return forFieldInstruction(
- lookup, appView.appInfo().lookupStaticTarget(lookup.clazz, lookup), invocationContext);
+ lookup, appView.appInfo().lookupStaticTarget(lookup.holder, lookup), invocationContext);
}
public ConstraintWithTarget forStore() {
@@ -269,7 +268,7 @@
private ConstraintWithTarget forFieldInstruction(
DexField field, DexEncodedField target, DexType invocationContext) {
// Resolve the field if possible and decide whether the instruction can inlined.
- DexType fieldHolder = graphLense.lookupType(field.clazz);
+ DexType fieldHolder = graphLense.lookupType(field.holder);
DexClass fieldClass = appView.definitionFor(fieldHolder);
if (target != null && fieldClass != null) {
ConstraintWithTarget fieldConstraintWithTarget =
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
index 0d5a895..36e9f25 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/MemberValuePropagation.java
@@ -42,7 +42,7 @@
public class MemberValuePropagation {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private enum RuleType {
NONE,
@@ -61,7 +61,7 @@
}
}
- public MemberValuePropagation(AppView<? extends AppInfoWithLiveness> appView) {
+ public MemberValuePropagation(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
}
@@ -95,7 +95,7 @@
DexField field = rule.getReturnValue().getField();
assert typeLattice
== TypeLatticeElement.fromDexType(field.type, Nullability.maybeNull(), appView.appInfo());
- DexEncodedField staticField = appView.appInfo().lookupStaticTarget(field.clazz, field);
+ DexEncodedField staticField = appView.appInfo().lookupStaticTarget(field.holder, field);
if (staticField != null) {
Value value = code.createValue(typeLattice, instruction.getLocalInfo());
replacement =
@@ -104,7 +104,7 @@
code.method.getMutableOptimizationInfo().markUseIdentifierNameString();
}
} else {
- throw new CompilationError(field.clazz.toSourceString() + "." + field.name.toString()
+ throw new CompilationError(field.holder.toSourceString() + "." + field.name.toString()
+ " used in assumevalues rule does not exist.");
}
}
@@ -185,7 +185,7 @@
InstructionListIterator iterator,
InvokeMethod current) {
DexMethod invokedMethod = current.getInvokedMethod();
- DexType invokedHolder = invokedMethod.getHolder();
+ DexType invokedHolder = invokedMethod.holder;
if (!invokedHolder.isClassType()) {
return;
}
@@ -261,7 +261,7 @@
DexField field = current.getField();
// TODO(b/123857022): Should be able to use definitionFor().
- DexEncodedField target = appView.appInfo().lookupStaticTarget(field.getHolder(), field);
+ DexEncodedField target = appView.appInfo().lookupStaticTarget(field.holder, field);
if (target == null || appView.appInfo().neverPropagateValue.contains(target.field)) {
return;
}
@@ -295,10 +295,10 @@
// be updated outside the class constructor, e.g. via reflections), it is safe
// to assume that the static-get instruction reads the value it initialized value
// in class initializer and is never null.
- DexClass holderDefinition = appView.definitionFor(field.getHolder());
+ DexClass holderDefinition = appView.definitionFor(field.holder);
if (holderDefinition != null
&& holderDefinition.accessFlags.isFinal()
- && !field.getHolder().initializationOfParentTypesMayHaveSideEffects(appView.appInfo())) {
+ && !field.holder.initializationOfParentTypesMayHaveSideEffects(appView.appInfo())) {
Value outValue = current.dest();
DexEncodedMethod classInitializer = holderDefinition.getClassInitializer();
if (classInitializer != null && !isProcessedConcurrently.test(classInitializer)) {
@@ -324,8 +324,8 @@
// TODO(b/123857022): Should be possible to use definitionFor().
DexEncodedField target =
current.isInstancePut()
- ? appView.appInfo().lookupInstanceTarget(field.getHolder(), field)
- : appView.appInfo().lookupStaticTarget(field.getHolder(), field);
+ ? appView.appInfo().lookupInstanceTarget(field.holder, field)
+ : appView.appInfo().lookupStaticTarget(field.holder, field);
if (target == null || appView.appInfo().neverPropagateValue.contains(target.field)) {
return;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
index 2a1092e..ec338ca 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/NonNullTracker.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.ir.code.DominatorTree.Assumption.MAY_HAVE_UNREACHABLE_BLOCKS;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexMethod;
@@ -23,7 +24,6 @@
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.conversion.OptimizationFeedback;
-import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Sets;
import it.unimi.dsi.fastutil.ints.IntArrayList;
@@ -41,11 +41,11 @@
public class NonNullTracker {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<? extends AppInfo> appView;
private final Set<DexMethod> libraryMethodsReturningNonNull;
public NonNullTracker(
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<? extends AppInfo> appView,
Set<DexMethod> libraryMethodsReturningNonNull) {
this.appView = appView;
this.libraryMethodsReturningNonNull = libraryMethodsReturningNonNull;
@@ -120,11 +120,14 @@
knownToBeNonNullValues.add(knownToBeNonNullValue);
}
}
- if (current.isInvokeMethod() && !current.isInvokePolymorphic()) {
+ if (current.isInvokeMethod()
+ && !current.isInvokePolymorphic()
+ && appView.appInfo().hasLiveness()) {
DexEncodedMethod singleTarget =
current
.asInvokeMethod()
- .lookupSingleTarget(appView.appInfo(), code.method.method.getHolder());
+ .lookupSingleTarget(
+ appView.appInfo().withLiveness(), code.method.method.holder);
if (singleTarget != null
&& singleTarget.getOptimizationInfo().getNonNullParamOnNormalExits() != null) {
BitSet facts = singleTarget.getOptimizationInfo().getNonNullParamOnNormalExits();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
index a7ec086..f5fca72 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Outliner.java
@@ -114,7 +114,7 @@
static final int MAX_IN_SIZE = 5; // Avoid using ranged calls for outlined code.
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final InliningConstraints inliningConstraints;
private abstract static class OutlineInstruction {
@@ -902,7 +902,7 @@
private DexType argumentTypeFromInvoke(InvokeMethod invoke, int index) {
assert invoke.isInvokeMethodWithReceiver() || invoke.isInvokePolymorphic();
if (index == 0) {
- return invoke.getInvokedMethod().getHolder();
+ return invoke.getInvokedMethod().holder;
}
DexProto methodProto;
if (invoke.isInvokePolymorphic()) {
@@ -1199,7 +1199,7 @@
}
}
- public Outliner(AppView<? extends AppInfoWithLiveness> appView, IRConverter converter) {
+ public Outliner(AppView<AppInfoWithLiveness> appView, IRConverter converter) {
this.appView = appView;
this.inliningConstraints = new InliningConstraints(appView, GraphLense.getIdentityLense());
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
index e298873..5c55d31 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/RedundantFieldLoadElimination.java
@@ -79,7 +79,7 @@
private boolean couldBeVolatile(DexField field) {
if (!appView.enableWholeProgramOptimizations()
- && field.getHolder() != method.method.getHolder()) {
+ && field.holder != method.method.holder) {
return true;
}
DexEncodedField definition = appView.definitionFor(field);
@@ -187,7 +187,7 @@
FieldAndObject fieldAndObject = new FieldAndObject(field, object);
activeInstanceFields.remove(fieldAndObject);
} else if (instruction.isStaticPut()) {
- if (field.clazz != code.method.method.holder) {
+ if (field.holder != code.method.method.holder) {
// Accessing a static field on a different object could cause <clinit> to run which
// could modify any static field on any other object.
activeStaticFields.clear();
@@ -195,7 +195,7 @@
activeStaticFields.remove(field);
}
} else if (instruction.isStaticGet()) {
- if (field.clazz != code.method.method.holder) {
+ if (field.holder != code.method.method.holder) {
// Accessing a static field on a different object could cause <clinit> to run which
// could modify any static field on any other object.
activeStaticFields.clear();
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index bd0fdea..e71def5 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -76,7 +76,7 @@
}
// Rewrite getClass() call to const-class if the type of the given instance is effectively final.
- public static void rewriteGetClass(AppView<? extends AppInfoWithLiveness> appView, IRCode code) {
+ public static void rewriteGetClass(AppView<AppInfoWithLiveness> appView, IRCode code) {
InstructionIterator it = code.instructionIterator();
DexItemFactory dexItemFactory = appView.dexItemFactory();
while (it.hasNext()) {
@@ -125,7 +125,7 @@
|| (!in.isPhi() && in.definition.isCreatingInstanceOrArray())) {
// Make sure the target (base) type is visible.
ConstraintWithTarget constraints =
- ConstraintWithTarget.classIsVisible(code.method.method.getHolder(), baseType, appView);
+ ConstraintWithTarget.classIsVisible(code.method.method.holder, baseType, appView);
if (constraints == ConstraintWithTarget.NEVER) {
continue;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
index a20539c..869e159 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/SwitchMapCollector.java
@@ -17,7 +17,6 @@
import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
-import java.util.Arrays;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@@ -60,13 +59,13 @@
*/
public class SwitchMapCollector {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final DexString switchMapPrefix;
private final DexType intArrayType;
private final Map<DexField, Int2ReferenceMap<DexField>> switchMaps = new IdentityHashMap<>();
- public SwitchMapCollector(AppView<? extends AppInfoWithLiveness> appView) {
+ public SwitchMapCollector(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
switchMapPrefix = appView.dexItemFactory().createString("$SwitchMap$");
intArrayType = appView.dexItemFactory().createType("[I");
@@ -87,7 +86,7 @@
if (!clazz.accessFlags.isSynthetic() && !clazz.hasClassInitializer()) {
return;
}
- List<DexEncodedField> switchMapFields = Arrays.stream(clazz.staticFields())
+ List<DexEncodedField> switchMapFields = clazz.staticFields().stream()
.filter(this::maybeIsSwitchMap).collect(Collectors.toList());
if (!switchMapFields.isEmpty()) {
IRCode initializer = clazz.getClassInitializer().buildIR(appView, clazz.origin);
@@ -125,7 +124,7 @@
return;
}
DexField enumField = enumGet.asStaticGet().getField();
- if (!appView.definitionFor(enumField.getHolder()).accessFlags.isEnum()) {
+ if (!appView.definitionFor(enumField.holder).accessFlags.isEnum()) {
return;
}
if (switchMap.put(integerIndex, enumField) != null) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/SwitchUtils.java b/src/main/java/com/android/tools/r8/ir/optimize/SwitchUtils.java
index 7331b00..8313b09 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/SwitchUtils.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/SwitchUtils.java
@@ -58,7 +58,7 @@
* and {@link SwitchMapCollector} for details.
*/
public static EnumSwitchInfo analyzeSwitchOverEnum(
- Instruction switchInsn, AppView<? extends AppInfoWithLiveness> appView) {
+ Instruction switchInsn, AppView<AppInfoWithLiveness> appView) {
AppInfoWithLiveness appInfo = appView.appInfo();
Instruction input = switchInsn.inValues().get(0).definition;
if (input == null || !input.isArrayGet()) {
@@ -92,7 +92,7 @@
}
// Due to member rebinding, only the fields are certain to provide the actual enums
// class.
- DexType enumType = indexMap.values().iterator().next().getHolder();
+ DexType enumType = indexMap.values().iterator().next().holder;
Reference2IntMap<DexField> ordinalsMap = appInfo.getOrdinalsMapFor(enumType);
if (ordinalsMap == null) {
return null;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
index 4daeb9e..c550118 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UninstantiatedTypeOptimization.java
@@ -105,7 +105,7 @@
}
}
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final DexItemFactory dexItemFactory;
private final InternalOptions options;
@@ -114,7 +114,7 @@
private int numberOfInvokesWithNullReceiver = 0;
public UninstantiatedTypeOptimization(
- AppView<? extends AppInfoWithLiveness> appView, InternalOptions options) {
+ AppView<AppInfoWithLiveness> appView, InternalOptions options) {
this.appView = appView;
this.dexItemFactory = appView.dexItemFactory();
this.options = options;
@@ -459,7 +459,7 @@
// We also need to be sure that this field instruction cannot trigger static class
// initialization.
- if (field.field.clazz != code.method.method.holder) {
+ if (field.field.holder != code.method.method.holder) {
DexClass enclosingClass = appView.definitionFor(code.method.method.holder);
if (enclosingClass == null
|| enclosingClass.classInitializationMayHaveSideEffects(appView.appInfo())) {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
index 96bce47..ad5f3be 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/UnusedArgumentsCollector.java
@@ -40,7 +40,7 @@
public class UnusedArgumentsCollector {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final BiMap<DexMethod, DexMethod> methodMapping = HashBiMap.create();
private final Map<DexMethod, RemovedArgumentsInfo> removedArguments = new IdentityHashMap<>();
@@ -81,7 +81,7 @@
}
}
- public UnusedArgumentsCollector(AppView<? extends AppInfoWithLiveness> appView) {
+ public UnusedArgumentsCollector(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
index da18d38..10508db 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliner.java
@@ -27,12 +27,11 @@
public final class ClassInliner {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final LambdaRewriter lambdaRewriter;
private final ConcurrentHashMap<DexClass, Boolean> knownClasses = new ConcurrentHashMap<>();
- public ClassInliner(
- AppView<? extends AppInfoWithLiveness> appView, LambdaRewriter lambdaRewriter) {
+ public ClassInliner(AppView<AppInfoWithLiveness> appView, LambdaRewriter lambdaRewriter) {
this.appView = appView;
this.lambdaRewriter = lambdaRewriter;
}
@@ -115,7 +114,7 @@
// }
//
public final void processMethodCode(
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<AppInfoWithLiveness> appView,
CodeRewriter codeRewriter,
StringOptimizer stringOptimizer,
DexEncodedMethod method,
@@ -201,7 +200,7 @@
}
}
- private boolean isClassEligible(AppView<? extends AppInfoWithLiveness> appView, DexClass clazz) {
+ private boolean isClassEligible(AppView<AppInfoWithLiveness> appView, DexClass clazz) {
Boolean eligible = knownClasses.get(clazz);
if (eligible == null) {
Boolean computed = computeClassEligible(appView, clazz);
@@ -216,8 +215,7 @@
// - is not an abstract class or interface
// - does not declare finalizer
// - does not trigger any static initializers except for its own
- private boolean computeClassEligible(
- AppView<? extends AppInfoWithLiveness> appView, DexClass clazz) {
+ private boolean computeClassEligible(AppView<AppInfoWithLiveness> appView, DexClass clazz) {
if (clazz == null
|| clazz.isLibraryClass()
|| clazz.accessFlags.isAbstract()
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
index f36a132..79e4f2d 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/classinliner/InlineCandidateProcessor.java
@@ -58,7 +58,7 @@
private static final ImmutableSet<If.Type> ALLOWED_ZERO_TEST_TYPES =
ImmutableSet.of(If.Type.EQ, If.Type.NE);
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final LambdaRewriter lambdaRewriter;
private final Inliner inliner;
private final Predicate<DexClass> isClassEligible;
@@ -81,7 +81,7 @@
private int estimatedCombinedSizeForInlining = 0;
InlineCandidateProcessor(
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<AppInfoWithLiveness> appView,
LambdaRewriter lambdaRewriter,
Inliner inliner,
Predicate<DexClass> isClassEligible,
@@ -207,7 +207,7 @@
// of class inlining
//
- if (eligibleClassDefinition.instanceFields().length > 0) {
+ if (eligibleClassDefinition.instanceFields().size() > 0) {
return false;
}
if (eligibleClassDefinition.type.hasSubtypes()) {
@@ -253,7 +253,7 @@
if (user.isInstanceGet()
|| (user.isInstancePut() && user.asInstancePut().value() != eligibleInstance)) {
DexField field = user.asFieldInstruction().getField();
- if (field.clazz == eligibleClass
+ if (field.holder == eligibleClass
&& eligibleClassDefinition.lookupInstanceField(field) != null) {
// Since class inliner currently only supports classes directly extending
// java.lang.Object, we don't need to worry about fields defined in superclasses.
@@ -511,7 +511,7 @@
+ "` after field reads removed: "
+ user);
}
- if (user.asInstancePut().getField().clazz != eligibleClass) {
+ if (user.asInstancePut().getField().holder != eligibleClass) {
throw new Unreachable(
"Unexpected field write left in method `"
+ method.method.toSourceString()
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/CaptureSignature.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/CaptureSignature.java
index ede37b1..5a39e71 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/CaptureSignature.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/CaptureSignature.java
@@ -16,6 +16,7 @@
import java.util.Arrays;
import java.util.BitSet;
import java.util.Comparator;
+import java.util.List;
import java.util.function.IntFunction;
// While mapping fields representing lambda captures we rearrange fields to make sure
@@ -106,8 +107,8 @@
}
// Compute capture signature based on lambda class capture fields.
- public static String getCaptureSignature(DexEncodedField[] fields) {
- return getCaptureSignature(fields.length, i -> fields[i].field.type);
+ public static String getCaptureSignature(List<DexEncodedField> fields) {
+ return getCaptureSignature(fields.size(), i -> fields.get(i).field.type);
}
// Compute capture signature based on type list.
@@ -118,7 +119,7 @@
// Having a list of fields of lambda captured values, maps one of them into
// an index of the appropriate field in normalized capture signature.
public static int mapFieldIntoCaptureIndex(
- String capture, DexEncodedField[] lambdaFields, DexField fieldToMap) {
+ String capture, List<DexEncodedField> lambdaFields, DexField fieldToMap) {
char fieldKind = fieldToMap.type.toShorty();
int numberOfSameCaptureKind = 0;
int result = -1;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java
index 854ac19..edee200 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/CodeProcessor.java
@@ -281,9 +281,9 @@
private void handle(InstanceGet instanceGet) {
DexField field = instanceGet.getField();
- Strategy strategy = strategyProvider.apply(field.clazz);
+ Strategy strategy = strategyProvider.apply(field.holder);
if (strategy.isValidInstanceFieldRead(this, field)) {
- if (field.clazz != this.method.method.holder) {
+ if (field.holder != this.method.method.holder) {
// Only rewrite references to lambda classes if we are outside the class.
process(strategy, instanceGet);
}
@@ -298,9 +298,9 @@
private void handle(InstancePut instancePut) {
DexField field = instancePut.getField();
- Strategy strategy = strategyProvider.apply(field.clazz);
+ Strategy strategy = strategyProvider.apply(field.holder);
if (strategy.isValidInstanceFieldWrite(this, field)) {
- if (field.clazz != this.method.method.holder) {
+ if (field.holder != this.method.method.holder) {
// Only rewrite references to lambda classes if we are outside the class.
process(strategy, instancePut);
}
@@ -315,29 +315,29 @@
private void handle(StaticGet staticGet) {
DexField field = staticGet.getField();
- Strategy strategy = strategyProvider.apply(field.clazz);
+ Strategy strategy = strategyProvider.apply(field.holder);
if (strategy.isValidStaticFieldRead(this, field)) {
- if (field.clazz != this.method.method.holder) {
+ if (field.holder != this.method.method.holder) {
// Only rewrite references to lambda classes if we are outside the class.
process(strategy, staticGet);
}
} else {
lambdaChecker.accept(field.type);
- lambdaChecker.accept(field.clazz);
+ lambdaChecker.accept(field.holder);
}
}
private void handle(StaticPut staticPut) {
DexField field = staticPut.getField();
- Strategy strategy = strategyProvider.apply(field.clazz);
+ Strategy strategy = strategyProvider.apply(field.holder);
if (strategy.isValidStaticFieldWrite(this, field)) {
- if (field.clazz != this.method.method.holder) {
+ if (field.holder != this.method.method.holder) {
// Only rewrite references to lambda classes if we are outside the class.
process(strategy, staticPut);
}
} else {
lambdaChecker.accept(field.type);
- lambdaChecker.accept(field.clazz);
+ lambdaChecker.accept(field.holder);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
index b0af387..6b5625c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
@@ -110,16 +110,16 @@
return lambdas.get(lambda).id;
}
- protected final DexEncodedField[] lambdaCaptureFields(DexType lambda) {
+ protected final List<DexEncodedField> lambdaCaptureFields(DexType lambda) {
assert lambdas.containsKey(lambda);
return lambdas.get(lambda).clazz.instanceFields();
}
protected final DexEncodedField lambdaSingletonField(DexType lambda) {
assert lambdas.containsKey(lambda);
- DexEncodedField[] fields = lambdas.get(lambda).clazz.staticFields();
- assert fields.length < 2;
- return fields.length == 0 ? null : fields[0];
+ List<DexEncodedField> fields = lambdas.get(lambda).clazz.staticFields();
+ assert fields.size() < 2;
+ return fields.size() == 0 ? null : fields.get(0);
}
// Contains less than 2 elements?
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index 66ae73a..20f0b6a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -146,7 +146,7 @@
// We do this before methods are being processed to guarantee stable order of
// lambdas inside each group.
public final void collectGroupCandidates(
- DexApplication app, AppView<? extends AppInfoWithLiveness> appView) {
+ DexApplication app, AppView<AppInfoWithLiveness> appView) {
// Collect lambda groups.
app.classes().stream()
.filter(cls -> !appView.appInfo().isPinned(cls.type))
@@ -154,7 +154,8 @@
cls ->
cls.hasKotlinInfo()
&& cls.getKotlinInfo().isSyntheticClass()
- && cls.getKotlinInfo().asSyntheticClass().isLambda())
+ && cls.getKotlinInfo().asSyntheticClass().isLambda()
+ && KotlinLambdaGroupIdFactory.hasValidAnnotations(kotlin, cls))
.sorted((a, b) -> a.type.slowCompareTo(b.type)) // Ensure stable ordering.
.forEachOrdered(
lambda -> {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaTypeVisitor.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaTypeVisitor.java
index 05c71e6..7422bc0 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaTypeVisitor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaTypeVisitor.java
@@ -87,8 +87,8 @@
void accept(DexField field, DexType holderToIgnore) {
accept(field.type);
- if (holderToIgnore != field.clazz) {
- accept(field.clazz);
+ if (holderToIgnore != field.holder) {
+ accept(field.holder);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java
index 2bdc441..db9f04e 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/JStyleLambdaGroup.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.utils.ThrowingConsumer;
import com.google.common.collect.Lists;
+import java.util.List;
import java.util.function.IntFunction;
// Represents a j-style lambda group created to combine several lambda classes
@@ -152,8 +153,8 @@
}
@Override
- int getInstanceInitializerSize(DexEncodedField[] captures) {
- return captures.length + 2;
+ int getInstanceInitializerSize(List<DexEncodedField> captures) {
+ return captures.size() + 2;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java
index ee0b800..587e172 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KStyleLambdaGroup.java
@@ -27,6 +27,7 @@
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.utils.ThrowingConsumer;
import com.google.common.collect.Lists;
+import java.util.List;
import java.util.function.IntFunction;
// Represents a k-style lambda group created to combine several lambda classes
@@ -158,8 +159,8 @@
}
@Override
- int getInstanceInitializerSize(DexEncodedField[] captures) {
- return captures.length + 3;
+ int getInstanceInitializerSize(List<DexEncodedField> captures) {
+ return captures.size() + 3;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaClassValidator.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaClassValidator.java
index 2385f35..16430eb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaClassValidator.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaClassValidator.java
@@ -29,6 +29,7 @@
import com.android.tools.r8.ir.optimize.lambda.LambdaGroup.LambdaStructureError;
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.utils.ThrowingConsumer;
+import java.util.List;
// Encapsulates the logic of deep-checking of the lambda class assumptions.
//
@@ -118,14 +119,14 @@
}
}
- abstract int getInstanceInitializerSize(DexEncodedField[] captures);
+ abstract int getInstanceInitializerSize(List<DexEncodedField> captures);
abstract int validateInstanceInitializerEpilogue(
com.android.tools.r8.code.Instruction[] instructions, int index) throws LambdaStructureError;
private void validateInstanceInitializer(DexClass lambda, Code code)
throws LambdaStructureError {
- DexEncodedField[] captures = lambda.instanceFields();
+ List<DexEncodedField> captures = lambda.instanceFields();
com.android.tools.r8.code.Instruction[] instructions = code.asDexCode().instructions;
int index = 0;
@@ -142,66 +143,66 @@
assert index == instructions.length;
}
- private int validateInstanceInitializerParameterMapping(DexEncodedField[] captures,
+ private int validateInstanceInitializerParameterMapping(List<DexEncodedField> captures,
Instruction[] instructions, int index) throws LambdaStructureError {
int wideFieldsSeen = 0;
for (DexEncodedField field : captures) {
switch (field.field.type.toShorty()) {
case 'Z':
- if (!(instructions[index] instanceof IputBoolean) ||
- (instructions[index].getField() != field.field) ||
- (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
+ if (!(instructions[index] instanceof IputBoolean)
+ || (instructions[index].getField() != field.field)
+ || (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
}
break;
case 'B':
- if (!(instructions[index] instanceof IputByte) ||
- (instructions[index].getField() != field.field) ||
- (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
+ if (!(instructions[index] instanceof IputByte)
+ || (instructions[index].getField() != field.field)
+ || (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
}
break;
case 'S':
- if (!(instructions[index] instanceof IputShort) ||
- (instructions[index].getField() != field.field) ||
- (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
+ if (!(instructions[index] instanceof IputShort)
+ || (instructions[index].getField() != field.field)
+ || (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
}
break;
case 'C':
- if (!(instructions[index] instanceof IputChar) ||
- (instructions[index].getField() != field.field) ||
- (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
+ if (!(instructions[index] instanceof IputChar)
+ || (instructions[index].getField() != field.field)
+ || (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
}
break;
case 'I':
case 'F':
- if (!(instructions[index] instanceof Iput) ||
- (instructions[index].getField() != field.field) ||
- (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
+ if (!(instructions[index] instanceof Iput)
+ || (instructions[index].getField() != field.field)
+ || (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
}
break;
case 'J':
case 'D':
- if (!(instructions[index] instanceof IputWide) ||
- (instructions[index].getField() != field.field) ||
- (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
+ if (!(instructions[index] instanceof IputWide)
+ || (instructions[index].getField() != field.field)
+ || (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
}
wideFieldsSeen++;
break;
case 'L':
- if (!(instructions[index] instanceof IputObject) ||
- (instructions[index].getField() != field.field) ||
- (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
+ if (!(instructions[index] instanceof IputObject)
+ || (instructions[index].getField() != field.field)
+ || (((Format22c) instructions[index]).A != (index + 1 + wideFieldsSeen))) {
throw structureError(LAMBDA_INIT_CODE_VERIFICATION_FAILED);
}
break;
@@ -221,8 +222,8 @@
if (instructions.length != 4) {
throw structureError(LAMBDA_CLINIT_CODE_VERIFICATION_FAILED);
}
- if (!(instructions[0] instanceof com.android.tools.r8.code.NewInstance) ||
- ((com.android.tools.r8.code.NewInstance) instructions[0]).getType() != lambda.type) {
+ if (!(instructions[0] instanceof com.android.tools.r8.code.NewInstance)
+ || ((com.android.tools.r8.code.NewInstance) instructions[0]).getType() != lambda.type) {
throw structureError(LAMBDA_CLINIT_CODE_VERIFICATION_FAILED);
}
if (!(instructions[1] instanceof com.android.tools.r8.code.InvokeDirect
@@ -230,8 +231,8 @@
|| !isLambdaInitializerMethod(lambda, instructions[1].getMethod())) {
throw structureError(LAMBDA_CLINIT_CODE_VERIFICATION_FAILED);
}
- if (!(instructions[2] instanceof SputObject) ||
- !isLambdaSingletonField(lambda, instructions[2].getField())) {
+ if (!(instructions[2] instanceof SputObject)
+ || !isLambdaSingletonField(lambda, instructions[2].getField())) {
throw structureError(LAMBDA_CLINIT_CODE_VERIFICATION_FAILED);
}
if (!(instructions[3] instanceof ReturnVoid)) {
@@ -240,12 +241,15 @@
}
private boolean isLambdaSingletonField(DexClass lambda, DexField field) {
- return field.type == lambda.type && field.clazz == lambda.type &&
- field.name == kotlin.functional.kotlinStyleLambdaInstanceName;
+ return field.type == lambda.type
+ && field.holder == lambda.type
+ && field.name == kotlin.functional.kotlinStyleLambdaInstanceName;
}
private boolean isLambdaInitializerMethod(DexClass holder, DexMethod method) {
- return method.holder == holder.type && method.name == kotlin.factory.constructorMethodName &&
- method.proto.parameters.isEmpty() && method.proto.returnType == kotlin.factory.voidType;
+ return method.holder == holder.type
+ && method.name == kotlin.factory.constructorMethodName
+ && method.proto.parameters.isEmpty()
+ && method.proto.returnType == kotlin.factory.voidType;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
index 144487b..48967c3 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupCodeStrategy.java
@@ -48,7 +48,7 @@
@Override
public boolean isValidStaticFieldWrite(CodeProcessor context, DexField field) {
- DexType lambda = field.clazz;
+ DexType lambda = field.holder;
assert group.containsLambda(lambda);
// Only support writes to singleton static field named 'INSTANCE' from lambda
// static class initializer.
@@ -60,7 +60,7 @@
@Override
public boolean isValidStaticFieldRead(CodeProcessor context, DexField field) {
- DexType lambda = field.clazz;
+ DexType lambda = field.holder;
assert group.containsLambda(lambda);
// Support all reads of singleton static field named 'INSTANCE'.
return field.name == context.kotlin.functional.kotlinStyleLambdaInstanceName &&
@@ -69,7 +69,7 @@
@Override
public boolean isValidInstanceFieldWrite(CodeProcessor context, DexField field) {
- DexType lambda = field.clazz;
+ DexType lambda = field.holder;
DexMethod method = context.method.method;
assert group.containsLambda(lambda);
// Support writes to capture instance fields inside lambda constructor only.
@@ -78,7 +78,7 @@
@Override
public boolean isValidInstanceFieldRead(CodeProcessor context, DexField field) {
- assert group.containsLambda(field.clazz);
+ assert group.containsLambda(field.holder);
// Support all reads from capture instance fields.
return true;
}
@@ -157,7 +157,7 @@
new InstanceGet(
createValueForType(context, fieldType),
instanceGet.object(),
- mapCaptureField(context.factory, field.clazz, field));
+ mapCaptureField(context.factory, field.holder, field));
context.instructions().replaceCurrentInstruction(newInstanceGet);
if (fieldType.isPrimitiveType() || fieldType == context.factory.objectType) {
@@ -270,6 +270,6 @@
// Map lambda class initializer into lambda group class initializer.
private DexField mapSingletonInstanceField(DexItemFactory factory, DexField field) {
- return group.getSingletonInstanceField(factory, group.lambdaId(field.clazz));
+ return group.getSingletonInstanceField(factory, group.lambdaId(field.holder));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupIdFactory.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupIdFactory.java
index 4b8290e..7f7643b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupIdFactory.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/kotlin/KotlinLambdaGroupIdFactory.java
@@ -87,6 +87,21 @@
return null;
}
+ public static boolean hasValidAnnotations(Kotlin kotlin, DexClass lambda) {
+ if (!lambda.annotations.isEmpty()) {
+ for (DexAnnotation annotation : lambda.annotations.annotations) {
+ if (DexAnnotation.isSignatureAnnotation(annotation, kotlin.factory)) {
+ continue;
+ }
+ if (annotation.annotation.type == kotlin.metadata.kotlinMetadataType) {
+ continue;
+ }
+ return false;
+ }
+ }
+ return true;
+ }
+
String validateAnnotations(Kotlin kotlin, DexClass lambda) throws LambdaStructureError {
String signature = null;
if (!lambda.annotations.isEmpty()) {
@@ -103,38 +118,40 @@
continue;
}
+ assert !hasValidAnnotations(kotlin, lambda);
throw new LambdaStructureError(
"unexpected annotation: " + annotation.annotation.type.toSourceString());
}
}
+ assert hasValidAnnotations(kotlin, lambda);
return signature;
}
void validateStaticFields(Kotlin kotlin, DexClass lambda) throws LambdaStructureError {
- DexEncodedField[] staticFields = lambda.staticFields();
- if (staticFields.length == 1) {
- DexEncodedField field = staticFields[0];
+ List<DexEncodedField> staticFields = lambda.staticFields();
+ if (staticFields.size() == 1) {
+ DexEncodedField field = staticFields.get(0);
if (field.field.name != kotlin.functional.kotlinStyleLambdaInstanceName ||
field.field.type != lambda.type || !field.accessFlags.isPublic() ||
!field.accessFlags.isFinal() || !field.accessFlags.isStatic()) {
throw new LambdaStructureError("unexpected static field " + field.toSourceString());
}
// No state if the lambda is a singleton.
- if (lambda.instanceFields().length > 0) {
+ if (lambda.instanceFields().size() > 0) {
throw new LambdaStructureError("has instance fields along with INSTANCE");
}
checkAccessFlags("static field access flags", field.accessFlags, SINGLETON_FIELD_FLAGS);
checkFieldAnnotations(field);
- } else if (staticFields.length > 1) {
+ } else if (staticFields.size() > 1) {
throw new LambdaStructureError(
- "only one static field max expected, found " + staticFields.length);
+ "only one static field max expected, found " + staticFields.size());
}
}
String validateInstanceFields(DexClass lambda, boolean accessRelaxed)
throws LambdaStructureError {
- DexEncodedField[] instanceFields = lambda.instanceFields();
+ List<DexEncodedField> instanceFields = lambda.instanceFields();
for (DexEncodedField field : instanceFields) {
checkAccessFlags("capture field access flags", field.accessFlags,
accessRelaxed ? CAPTURE_FIELD_FLAGS_RELAXED : CAPTURE_FIELD_FLAGS);
@@ -147,7 +164,7 @@
for (DexEncodedMethod method : lambda.directMethods()) {
if (method.isClassInitializer()) {
// We expect to see class initializer only if there is a singleton field.
- if (lambda.staticFields().length != 1) {
+ if (lambda.staticFields().size() != 1) {
throw new LambdaStructureError("has static initializer, but no singleton field");
}
checkAccessFlags(
@@ -163,15 +180,15 @@
// Lambda class is expected to have one constructor
// with parameters matching capture signature.
DexType[] parameters = method.method.proto.parameters.values;
- DexEncodedField[] instanceFields = lambda.instanceFields();
- if (parameters.length != instanceFields.length) {
+ List<DexEncodedField> instanceFields = lambda.instanceFields();
+ if (parameters.length != instanceFields.size()) {
throw new LambdaStructureError("constructor parameters don't match captured values.");
}
for (int i = 0; i < parameters.length; i++) {
// Kotlin compiler sometimes reshuffles the parameters so that their order
// in the constructor don't match order of capture fields. We could add
// support for it, but it happens quite rarely so don't bother for now.
- if (parameters[i] != instanceFields[i].field.type) {
+ if (parameters[i] != instanceFields.get(i).field.type) {
throw new LambdaStructureError(
"constructor parameters don't match captured values.", false);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
index 9473341..0265c5b 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
@@ -46,7 +46,7 @@
public final class ClassStaticizer {
- final AppView<? extends AppInfoWithLiveness> appView;
+ final AppView<AppInfoWithLiveness> appView;
final DexItemFactory factory;
final IRConverter converter;
@@ -85,7 +85,7 @@
}
DexType hostType() {
- return singletonField.field.clazz;
+ return singletonField.field.holder;
}
DexClass hostClass() {
@@ -103,7 +103,7 @@
// The map storing all the potential candidates for staticizing.
final ConcurrentHashMap<DexType, CandidateInfo> candidates = new ConcurrentHashMap<>();
- public ClassStaticizer(AppView<? extends AppInfoWithLiveness> appView, IRConverter converter) {
+ public ClassStaticizer(AppView<AppInfoWithLiveness> appView, IRConverter converter) {
this.appView = appView;
this.factory = appView.dexItemFactory();
this.converter = converter;
@@ -144,18 +144,18 @@
}
// High-level limitations on what classes we consider eligible.
- if (cls.isInterface() || // Must not be an interface or an abstract class.
- cls.accessFlags.isAbstract() ||
+ if (cls.isInterface() // Must not be an interface or an abstract class.
+ || cls.accessFlags.isAbstract()
// Don't support candidates with instance fields
- cls.instanceFields().length > 0 ||
+ || cls.instanceFields().size() > 0
// Only support classes directly extending java.lang.Object
- cls.superType != factory.objectType ||
+ || cls.superType != factory.objectType
// Instead of requiring the class being final,
// just ensure it does not have subtypes
- cls.type.hasSubtypes() ||
+ || cls.type.hasSubtypes()
// Staticizing classes implementing interfaces is more
// difficult, so don't support it until we really need it.
- !cls.interfaces.isEmpty()) {
+ || !cls.interfaces.isEmpty()) {
notEligible.add(cls.type);
}
});
@@ -312,7 +312,7 @@
if (instruction.isInstanceGet() || instruction.isInstancePut()) {
DexField fieldReferenced = instruction.asFieldInstruction().getField();
- CandidateInfo candidateInfo = candidates.get(fieldReferenced.clazz);
+ CandidateInfo candidateInfo = candidates.get(fieldReferenced.holder);
if (candidateInfo != null) {
// Reads/writes to instance field of the candidate class are not supported.
candidateInfo.invalidate();
@@ -324,7 +324,7 @@
private boolean isAllowedInHostClassInitializer(
DexType host, Instruction insn, IRCode code) {
- return (insn.isStaticPut() && insn.asStaticPut().getField().clazz == host) ||
+ return (insn.isStaticPut() && insn.asStaticPut().getField().holder == host) ||
insn.isConstNumber() ||
insn.isConstString() ||
(insn.isGoto() && insn.asGoto().isTrivialGotoToTheNextBlock(code)) ||
@@ -455,7 +455,7 @@
// Allow single assignment to a singleton field.
StaticPut staticPut = instruction.asStaticPut();
DexEncodedField fieldAccessed =
- appView.appInfo().lookupStaticTarget(staticPut.getField().clazz, staticPut.getField());
+ appView.appInfo().lookupStaticTarget(staticPut.getField().holder, staticPut.getField());
return fieldAccessed == info.singletonField;
}
@@ -470,7 +470,7 @@
return null;
}
- assert candidateInfo.singletonField == appView.appInfo().lookupStaticTarget(field.clazz, field)
+ assert candidateInfo.singletonField == appView.appInfo().lookupStaticTarget(field.holder, field)
: "Added reference after collectCandidates(...)?";
Value singletonValue = staticGet.dest();
@@ -574,7 +574,7 @@
}
private boolean registerField(DexField field) {
- registerTypeReference(field.clazz);
+ registerTypeReference(field.holder);
registerTypeReference(field.type);
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index 6331d5f..ec23f05 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -50,11 +50,10 @@
import java.util.concurrent.Future;
import java.util.function.BiConsumer;
import java.util.stream.Collectors;
-import java.util.stream.Stream;
final class StaticizingProcessor {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final ClassStaticizer classStaticizer;
private final ExecutorService executorService;
@@ -65,7 +64,7 @@
private final Map<DexType, DexType> candidateToHostMapping = new IdentityHashMap<>();
StaticizingProcessor(
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<AppInfoWithLiveness> appView,
ClassStaticizer classStaticizer,
ExecutorService executorService) {
this.appView = appView;
@@ -125,7 +124,7 @@
// CHECK: instance initializer used to create an instance is trivial.
// NOTE: Along with requirement that candidate does not have instance
// fields this should guarantee that the constructor is empty.
- assert candidateClass.instanceFields().length == 0;
+ assert candidateClass.instanceFields().size() == 0;
assert constructorUsed.isProcessed();
TrivialInitializer trivialInitializer =
constructorUsed.getOptimizationInfo().getTrivialInitializerInfo();
@@ -231,7 +230,7 @@
// extend java.lang.Object guarantees that the constructor is actually
// empty and does not need to be inlined.
assert candidateInfo.candidate.superType == factory().objectType;
- assert candidateInfo.candidate.instanceFields().length == 0;
+ assert candidateInfo.candidate.instanceFields().size() == 0;
Value singletonValue = instruction.outValue();
assert singletonValue != null;
@@ -319,7 +318,7 @@
// From staticizer's viewpoint, `sp` is trivial in the sense that it is composed of values that
// refer to the same singleton field. If so, we can safely relax the assertion; remove uses of
// field reads; remove quasi-trivial phis; and then remove original field reads.
- private boolean testAndcollectPhisComposedOfSameFieldRead(
+ private boolean testAndCollectPhisComposedOfSameFieldRead(
Set<Phi> phisToCheck, DexField field, Set<Phi> trivialPhis) {
for (Phi phi : phisToCheck) {
Set<Phi> chainedPhis = Sets.newIdentityHashSet();
@@ -336,7 +335,7 @@
}
}
if (!chainedPhis.isEmpty()) {
- if (!testAndcollectPhisComposedOfSameFieldRead(chainedPhis, field, trivialPhis)) {
+ if (!testAndCollectPhisComposedOfSameFieldRead(chainedPhis, field, trivialPhis)) {
return false;
}
}
@@ -353,7 +352,7 @@
// However, it may be not true if re-processing introduces phis after optimizing common suffix.
Set<Phi> trivialPhis = Sets.newIdentityHashSet();
boolean hasTrivialPhis =
- testAndcollectPhisComposedOfSameFieldRead(dest.uniquePhiUsers(), field, trivialPhis);
+ testAndCollectPhisComposedOfSameFieldRead(dest.uniquePhiUsers(), field, trivialPhis);
assert dest.numberOfPhiUsers() == 0 || hasTrivialPhis;
Set<Instruction> users = new HashSet<>(dest.uniqueUsers());
// If that is the case, method calls we want to fix up include users of those phis.
@@ -456,13 +455,13 @@
}
private DexField mapFieldIfMoved(DexField field) {
- DexType hostType = candidateToHostMapping.get(field.clazz);
+ DexType hostType = candidateToHostMapping.get(field.holder);
if (hostType != null) {
field = factory().createField(hostType, field.type, field.name);
}
hostType = candidateToHostMapping.get(field.type);
if (hostType != null) {
- field = factory().createField(field.clazz, hostType, field.name);
+ field = factory().createField(field.holder, hostType, field.name);
}
return field;
}
@@ -511,12 +510,13 @@
private boolean classMembersConflict(DexClass a, DexClass b) {
assert Streams.stream(a.methods()).allMatch(DexEncodedMethod::isStatic);
- assert a.instanceFields().length == 0;
- return Stream.of(a.staticFields()).anyMatch(fld -> b.lookupField(fld.field) != null) ||
- Streams.stream(a.methods()).anyMatch(method -> b.lookupMethod(method.method) != null);
+ assert a.instanceFields().size() == 0;
+ return a.staticFields().stream().anyMatch(fld -> b.lookupField(fld.field) != null)
+ || Streams.stream(a.methods()).anyMatch(method -> b.lookupMethod(method.method) != null);
}
- private void moveMembersIntoHost(Set<DexEncodedMethod> staticizedMethods,
+ private void moveMembersIntoHost(
+ Set<DexEncodedMethod> staticizedMethods,
DexProgramClass candidateClass,
DexType hostType, DexClass hostClass,
BiMap<DexMethod, DexMethod> methodMapping,
@@ -524,26 +524,36 @@
candidateToHostMapping.put(candidateClass.type, hostType);
// Process static fields.
- // Append fields first.
- if (candidateClass.staticFields().length > 0) {
- DexEncodedField[] oldFields = hostClass.staticFields();
- DexEncodedField[] extraFields = candidateClass.staticFields();
- DexEncodedField[] newFields = new DexEncodedField[oldFields.length + extraFields.length];
- System.arraycopy(oldFields, 0, newFields, 0, oldFields.length);
- System.arraycopy(extraFields, 0, newFields, oldFields.length, extraFields.length);
- hostClass.setStaticFields(newFields);
- }
-
- // Fixup field types.
- DexEncodedField[] staticFields = hostClass.staticFields();
- for (int i = 0; i < staticFields.length; i++) {
- DexEncodedField field = staticFields[i];
+ int numOfHostStaticFields = hostClass.staticFields().size();
+ DexEncodedField[] newFields =
+ candidateClass.staticFields().size() > 0
+ ? new DexEncodedField[numOfHostStaticFields + candidateClass.staticFields().size()]
+ : new DexEncodedField[numOfHostStaticFields];
+ List<DexEncodedField> oldFields = hostClass.staticFields();
+ for (int i = 0; i < oldFields.size(); i++) {
+ DexEncodedField field = oldFields.get(i);
DexField newField = mapCandidateField(field.field, candidateClass.type, hostType);
if (newField != field.field) {
- staticFields[i] = field.toTypeSubstitutedField(newField);
+ newFields[i] = field.toTypeSubstitutedField(newField);
fieldMapping.put(field.field, newField);
+ } else {
+ newFields[i] = field;
}
}
+ if (candidateClass.staticFields().size() > 0) {
+ List<DexEncodedField> extraFields = candidateClass.staticFields();
+ for (int i = 0; i < extraFields.size(); i++) {
+ DexEncodedField field = extraFields.get(i);
+ DexField newField = mapCandidateField(field.field, candidateClass.type, hostType);
+ if (newField != field.field) {
+ newFields[numOfHostStaticFields + i] = field.toTypeSubstitutedField(newField);
+ fieldMapping.put(field.field, newField);
+ } else {
+ newFields[numOfHostStaticFields + i] = field;
+ }
+ }
+ }
+ hostClass.setStaticFields(newFields);
// Process static methods.
List<DexEncodedMethod> extraMethods = candidateClass.directMethods();
@@ -567,9 +577,9 @@
}
private DexField mapCandidateField(DexField field, DexType candidateType, DexType hostType) {
- return field.clazz != candidateType && field.type != candidateType ? field
+ return field.holder != candidateType && field.type != candidateType ? field
: factory().createField(
- field.clazz == candidateType ? hostType : field.clazz,
+ field.holder == candidateType ? hostType : field.holder,
field.type == candidateType ? hostType : field.type,
field.name);
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
index 942265e..35ddb6f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/string/StringOptimizer.java
@@ -358,7 +358,7 @@
}
if (instr.isInvokeMethod()) {
DexMethod invokedMethod = instr.asInvokeMethod().getInvokedMethod();
- DexClass holder = appInfo.definitionFor(invokedMethod.getHolder());
+ DexClass holder = appInfo.definitionFor(invokedMethod.holder);
// For most cases, library call is not interesting, e.g.,
// System.out.println(...), String.valueOf(...), etc.
// If it's too broad, we can introduce black-list.
diff --git a/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java b/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
index d3cda4a..1fda335 100644
--- a/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
+++ b/src/main/java/com/android/tools/r8/jar/InliningConstraintVisitor.java
@@ -37,7 +37,7 @@
public class InliningConstraintVisitor extends MethodVisitor {
private final JarApplicationReader application;
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final GraphLense graphLense;
private final InliningConstraints inliningConstraints;
private final DexEncodedMethod method;
@@ -47,7 +47,7 @@
public InliningConstraintVisitor(
JarApplicationReader application,
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<AppInfoWithLiveness> appView,
GraphLense graphLense,
DexEncodedMethod method,
DexType invocationContext) {
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
index 1e7094d..00ec506 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMapper.java
@@ -217,7 +217,7 @@
public String originalNameOf(IndexedDexItem item) {
if (item instanceof DexField) {
- return lookupName(getRenamedFieldSignature((DexField) item), ((DexField) item).clazz);
+ return lookupName(getRenamedFieldSignature((DexField) item), ((DexField) item).holder);
} else if (item instanceof DexMethod) {
return lookupName(getRenamedMethodSignature((DexMethod) item), ((DexMethod) item).holder);
} else if (item instanceof DexType) {
@@ -255,7 +255,7 @@
}
public FieldSignature originalSignatureOf(DexField field) {
- String decoded = descriptorToJavaType(field.clazz.descriptor.toString());
+ String decoded = descriptorToJavaType(field.holder.descriptor.toString());
FieldSignature memberSignature = getRenamedFieldSignature(field);
ClassNaming classNaming = getClassNaming(decoded);
if (classNaming == null) {
diff --git a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
index c073bb5..92c07d1 100644
--- a/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ClassNameMinifier.java
@@ -39,7 +39,7 @@
class ClassNameMinifier {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final AppInfoWithLiveness appInfo;
private final ClassNamingStrategy classNamingStrategy;
private final PackageNamingStrategy packageNamingStrategy;
@@ -62,7 +62,7 @@
private final Namespace topLevelState;
ClassNameMinifier(
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<AppInfoWithLiveness> appView,
RootSet rootSet,
ClassNamingStrategy classNamingStrategy,
PackageNamingStrategy packageNamingStrategy,
diff --git a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
index e5f9218..96bba7a 100644
--- a/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/FieldNameMinifier.java
@@ -20,9 +20,7 @@
class FieldNameMinifier extends MemberNameMinifier<DexField, DexType> {
FieldNameMinifier(
- AppView<? extends AppInfoWithLiveness> appView,
- RootSet rootSet,
- MemberNamingStrategy strategy) {
+ AppView<AppInfoWithLiveness> appView, RootSet rootSet, MemberNamingStrategy strategy) {
super(appView, rootSet, strategy);
}
@@ -134,7 +132,7 @@
return;
}
// Now, `field` is reference. Find its definition and check if it's renamed.
- DexClass holder = appInfo.definitionFor(field.clazz);
+ DexClass holder = appInfo.definitionFor(field.holder);
// We don't care pruned types or library classes.
if (holder == null || holder.isLibraryClass()) {
return;
@@ -146,7 +144,7 @@
return;
}
assert definition.field != field;
- assert definition.field.clazz != field.clazz;
+ assert definition.field.holder != field.holder;
// If the definition is renamed,
if (renaming.containsKey(definition.field)) {
// Assign the same, renamed name as the definition to the reference.
diff --git a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
index 9479ab3..8468724 100644
--- a/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
+++ b/src/main/java/com/android/tools/r8/naming/IdentifierNameStringMarker.java
@@ -46,10 +46,10 @@
public class IdentifierNameStringMarker {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final Object2BooleanMap<DexReference> identifierNameStrings;
- public IdentifierNameStringMarker(AppView<? extends AppInfoWithLiveness> appView) {
+ public IdentifierNameStringMarker(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
// Note that this info is only available at AppInfoWithLiveness.
this.identifierNameStrings = appView.appInfo().identifierNameStrings;
@@ -84,7 +84,7 @@
return;
}
ThrowingInfo throwingInfo = ThrowingInfo.defaultForConstString(appView.options());
- DexType originHolder = code.method.method.getHolder();
+ DexType originHolder = code.method.method.holder;
ListIterator<BasicBlock> blocks = code.listIterator();
while (blocks.hasNext()) {
BasicBlock block = blocks.next();
diff --git a/src/main/java/com/android/tools/r8/naming/MemberNameMinifier.java b/src/main/java/com/android/tools/r8/naming/MemberNameMinifier.java
index 42e3f76..b6b50b9 100644
--- a/src/main/java/com/android/tools/r8/naming/MemberNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/MemberNameMinifier.java
@@ -22,7 +22,7 @@
abstract class MemberNameMinifier<MemberType, StateType extends CachedHashValueDexItem> {
- protected final AppView<? extends AppInfoWithLiveness> appView;
+ protected final AppView<AppInfoWithLiveness> appView;
protected final AppInfoWithLiveness appInfo;
protected final RootSet rootSet;
protected final InternalOptions options;
@@ -41,9 +41,7 @@
private final BiMap<DexType, NamingState<StateType, ?>> states = HashBiMap.create();
MemberNameMinifier(
- AppView<? extends AppInfoWithLiveness> appView,
- RootSet rootSet,
- MemberNamingStrategy strategy) {
+ AppView<AppInfoWithLiveness> appView, RootSet rootSet, MemberNamingStrategy strategy) {
this.appView = appView;
this.appInfo = appView.appInfo();
this.rootSet = rootSet;
diff --git a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
index 50b22b0..e9932e1 100644
--- a/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/MethodNameMinifier.java
@@ -94,9 +94,7 @@
private final MemberNamingStrategy strategy;
MethodNameMinifier(
- AppView<? extends AppInfoWithLiveness> appView,
- RootSet rootSet,
- MemberNamingStrategy strategy) {
+ AppView<AppInfoWithLiveness> appView, RootSet rootSet, MemberNamingStrategy strategy) {
super(appView, rootSet, strategy);
this.strategy = strategy;
equivalence =
diff --git a/src/main/java/com/android/tools/r8/naming/MinifiedNameMapPrinter.java b/src/main/java/com/android/tools/r8/naming/MinifiedNameMapPrinter.java
index e3d09b6..0fdeebc 100644
--- a/src/main/java/com/android/tools/r8/naming/MinifiedNameMapPrinter.java
+++ b/src/main/java/com/android/tools/r8/naming/MinifiedNameMapPrinter.java
@@ -72,7 +72,7 @@
}
}
- private void writeFields(DexEncodedField[] fields, StringBuilder out) {
+ private void writeFields(List<DexEncodedField> fields, StringBuilder out) {
for (DexEncodedField encodedField : fields) {
DexField field = encodedField.field;
DexString renamed = namingLens.lookupName(field);
diff --git a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
index f72efe1..18a23ba 100644
--- a/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
+++ b/src/main/java/com/android/tools/r8/naming/MinifiedRenaming.java
@@ -150,11 +150,11 @@
DexEncodedMethod directTarget = appInfo.lookupDirectTarget(item);
DexEncodedMethod virtualTarget = appInfo.lookupVirtualTarget(item.holder, item);
DexClass staticTargetHolder =
- staticTarget != null ? appInfo.definitionFor(staticTarget.method.getHolder()) : null;
+ staticTarget != null ? appInfo.definitionFor(staticTarget.method.holder) : null;
DexClass directTargetHolder =
- directTarget != null ? appInfo.definitionFor(directTarget.method.getHolder()) : null;
+ directTarget != null ? appInfo.definitionFor(directTarget.method.holder) : null;
DexClass virtualTargetHolder =
- virtualTarget != null ? appInfo.definitionFor(virtualTarget.method.getHolder()) : null;
+ virtualTarget != null ? appInfo.definitionFor(virtualTarget.method.holder) : null;
return (directTarget == null && staticTarget == null && virtualTarget == null)
|| (virtualTarget != null && virtualTarget.method == item)
|| (directTarget != null && directTarget.method == item)
diff --git a/src/main/java/com/android/tools/r8/naming/Minifier.java b/src/main/java/com/android/tools/r8/naming/Minifier.java
index 96b174e..0b7bf45 100644
--- a/src/main/java/com/android/tools/r8/naming/Minifier.java
+++ b/src/main/java/com/android/tools/r8/naming/Minifier.java
@@ -28,16 +28,14 @@
public class Minifier {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final AppInfoWithLiveness appInfo;
private final RootSet rootSet;
private final Set<DexCallSite> desugaredCallSites;
private final InternalOptions options;
public Minifier(
- AppView<? extends AppInfoWithLiveness> appView,
- RootSet rootSet,
- Set<DexCallSite> desugaredCallSites) {
+ AppView<AppInfoWithLiveness> appView, RootSet rootSet, Set<DexCallSite> desugaredCallSites) {
this.appView = appView;
this.appInfo = appView.appInfo();
this.rootSet = rootSet;
diff --git a/src/main/java/com/android/tools/r8/naming/NamingLens.java b/src/main/java/com/android/tools/r8/naming/NamingLens.java
index aecae1e..8488f09 100644
--- a/src/main/java/com/android/tools/r8/naming/NamingLens.java
+++ b/src/main/java/com/android/tools/r8/naming/NamingLens.java
@@ -79,7 +79,7 @@
public final DexField lookupField(DexField field, DexItemFactory dexItemFactory) {
return dexItemFactory.createField(
- lookupType(field.clazz, dexItemFactory),
+ lookupType(field.holder, dexItemFactory),
lookupType(field.type, dexItemFactory),
lookupName(field));
}
diff --git a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
index bd05b42..84c21f6 100644
--- a/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
+++ b/src/main/java/com/android/tools/r8/naming/ProguardMapMinifier.java
@@ -37,7 +37,7 @@
public class ProguardMapMinifier {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final AppInfoWithLiveness appInfo;
private final RootSet rootSet;
private final SeedMapper seedMapper;
@@ -45,7 +45,7 @@
private final DexItemFactory factory;
public ProguardMapMinifier(
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<AppInfoWithLiveness> appView,
RootSet rootSet,
SeedMapper seedMapper,
Set<DexCallSite> desugaredCallSites) {
diff --git a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
index 1f9570c..20f4bc2 100644
--- a/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
+++ b/src/main/java/com/android/tools/r8/naming/signature/GenericSignatureRewriter.java
@@ -28,17 +28,17 @@
public class GenericSignatureRewriter {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final AppInfoWithLiveness appInfo;
private final Map<DexType, DexString> renaming;
private final Reporter reporter;
- public GenericSignatureRewriter(AppView<? extends AppInfoWithLiveness> appView) {
+ public GenericSignatureRewriter(AppView<AppInfoWithLiveness> appView) {
this(appView, Maps.newIdentityHashMap());
}
public GenericSignatureRewriter(
- AppView<? extends AppInfoWithLiveness> appView, Map<DexType, DexString> renaming) {
+ AppView<AppInfoWithLiveness> appView, Map<DexType, DexString> renaming) {
this.appView = appView;
this.appInfo = appView.appInfo();
this.renaming = renaming;
diff --git a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
index 229471e..93c02ac 100644
--- a/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
+++ b/src/main/java/com/android/tools/r8/optimize/ClassAndMemberPublicizer.java
@@ -23,16 +23,14 @@
public final class ClassAndMemberPublicizer {
private final DexApplication application;
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final RootSet rootSet;
private final MethodPoolCollection methodPoolCollection;
private final PublicizedLenseBuilder lenseBuilder = PublicizerLense.createBuilder();
private ClassAndMemberPublicizer(
- DexApplication application,
- AppView<? extends AppInfoWithLiveness> appView,
- RootSet rootSet) {
+ DexApplication application, AppView<AppInfoWithLiveness> appView, RootSet rootSet) {
this.application = application;
this.appView = appView;
this.methodPoolCollection = new MethodPoolCollection(application);
@@ -49,7 +47,7 @@
ExecutorService executorService,
Timing timing,
DexApplication application,
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<AppInfoWithLiveness> appView,
RootSet rootSet)
throws ExecutionException {
return new ClassAndMemberPublicizer(application, appView, rootSet).run(executorService, timing);
@@ -125,7 +123,7 @@
accessFlags.promoteToPublic();
// Although the current method became public, it surely has the single virtual target.
encodedMethod.method.setSingleVirtualMethodCache(
- encodedMethod.method.getHolder(), encodedMethod);
+ encodedMethod.method.holder, encodedMethod);
return true;
}
diff --git a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
index cd3f27a..650d7ca 100644
--- a/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
+++ b/src/main/java/com/android/tools/r8/optimize/MemberRebindingAnalysis.java
@@ -36,7 +36,7 @@
private final MemberRebindingLense.Builder builder;
- public MemberRebindingAnalysis(AppView<? extends AppInfoWithLiveness> appView) {
+ public MemberRebindingAnalysis(AppView<AppInfoWithLiveness> appView) {
assert appView.graphLense().isContextFreeForMethods();
this.appInfo = appView.appInfo();
this.lense = appView.graphLense();
@@ -47,7 +47,7 @@
}
private DexMethod validTargetFor(DexMethod target, DexMethod original) {
- DexClass clazz = appInfo.definitionFor(target.getHolder());
+ DexClass clazz = appInfo.definitionFor(target.holder);
assert clazz != null;
if (searchInLibrary || !clazz.isLibraryClass()) {
return target;
@@ -55,25 +55,25 @@
DexType newHolder;
if (clazz.isInterface()) {
newHolder =
- firstLibraryClassForInterfaceTarget(target, original.getHolder(), DexClass::lookupMethod);
+ firstLibraryClassForInterfaceTarget(target, original.holder, DexClass::lookupMethod);
} else {
- newHolder = firstLibraryClass(target.getHolder(), original.getHolder());
+ newHolder = firstLibraryClass(target.holder, original.holder);
}
return appInfo.dexItemFactory.createMethod(newHolder, original.proto, original.name);
}
private DexField validTargetFor(DexField target, DexField original,
BiFunction<DexClass, DexField, DexEncodedField> lookup) {
- DexClass clazz = appInfo.definitionFor(target.getHolder());
+ DexClass clazz = appInfo.definitionFor(target.holder);
assert clazz != null;
if (searchInLibrary || !clazz.isLibraryClass()) {
return target;
}
DexType newHolder;
if (clazz.isInterface()) {
- newHolder = firstLibraryClassForInterfaceTarget(target, original.getHolder(), lookup);
+ newHolder = firstLibraryClassForInterfaceTarget(target, original.holder, lookup);
} else {
- newHolder = firstLibraryClass(target.getHolder(), original.getHolder());
+ newHolder = firstLibraryClass(target.holder, original.holder);
}
return appInfo.dexItemFactory.createField(newHolder, original.type, original.name);
}
@@ -113,15 +113,15 @@
}
private DexEncodedMethod classLookup(DexMethod method) {
- return appInfo.resolveMethodOnClass(method.getHolder(), method).asResultOfResolve();
+ return appInfo.resolveMethodOnClass(method.holder, method).asResultOfResolve();
}
private DexEncodedMethod interfaceLookup(DexMethod method) {
- return appInfo.resolveMethodOnInterface(method.getHolder(), method).asResultOfResolve();
+ return appInfo.resolveMethodOnInterface(method.holder, method).asResultOfResolve();
}
private DexEncodedMethod anyLookup(DexMethod method) {
- return appInfo.resolveMethod(method.getHolder(), method).asResultOfResolve();
+ return appInfo.resolveMethod(method.holder, method).asResultOfResolve();
}
private void computeMethodRebinding(
@@ -130,7 +130,7 @@
Type invokeType) {
for (DexMethod method : methodsWithContexts.keySet()) {
// We can safely ignore array types, as the corresponding methods are defined in a library.
- if (!method.getHolder().isClassType()) {
+ if (!method.holder.isClassType()) {
continue;
}
DexClass originalClass = appInfo.definitionFor(method.holder);
@@ -159,7 +159,7 @@
final DexEncodedMethod finalTarget = target;
Set<DexEncodedMethod> contexts = methodsWithContexts.get(method);
if (contexts.stream().anyMatch(context ->
- mayNeedBridgeForVisibility(context.method.getHolder(), finalTarget))) {
+ mayNeedBridgeForVisibility(context.method.holder, finalTarget))) {
target =
insertBridgeForVisibilityIfNeeded(
method, target, originalClass, targetClass, lookupTarget);
@@ -216,7 +216,7 @@
}
private boolean mayNeedBridgeForVisibility(DexType context, DexEncodedMethod method) {
- DexType holderType = method.method.getHolder();
+ DexType holderType = method.method.holder;
DexClass holder = appInfo.definitionFor(holderType);
if (holder == null) {
return false;
@@ -289,7 +289,7 @@
BiFunction<DexType, DexField, DexEncodedField> lookup,
BiFunction<DexClass, DexField, DexEncodedField> lookupTargetOnClass) {
for (DexField field : fieldsWithContexts.keySet()) {
- DexEncodedField target = lookup.apply(field.getHolder(), field);
+ DexEncodedField target = lookup.apply(field.holder, field);
// Rebind to the lowest library class or program class. Do not rebind accesses to fields that
// are not visible from the access context.
Set<DexEncodedMethod> contexts = fieldsWithContexts.get(field);
@@ -300,8 +300,8 @@
context ->
isMemberVisibleFromOriginalContext(
appInfo,
- context.method.getHolder(),
- target.field.clazz,
+ context.method.holder,
+ target.field.holder,
target.accessFlags))) {
builder.map(field,
lense.lookupField(validTargetFor(target.field, field, lookupTargetOnClass)));
diff --git a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
index f2e6c6d..8b6c7fa 100644
--- a/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
+++ b/src/main/java/com/android/tools/r8/optimize/VisibilityBridgeRemover.java
@@ -17,9 +17,9 @@
public class VisibilityBridgeRemover {
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
- public VisibilityBridgeRemover(AppView<? extends AppInfoWithLiveness> appView) {
+ public VisibilityBridgeRemover(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
}
@@ -73,7 +73,7 @@
if (kind == InvokeKind.SUPER) {
// This is a visibility forward, so check for the direct target.
DexEncodedMethod targetMethod =
- appView.appInfo().resolveMethod(target.getHolder(), target).asSingleTarget();
+ appView.appInfo().resolveMethod(target.holder, target).asSingleTarget();
if (targetMethod != null && targetMethod.accessFlags.isPublic()) {
if (Log.ENABLED) {
Log.info(
diff --git a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
index b6aa517..d164d91 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -429,22 +429,33 @@
private <S extends DexItem, T extends Descriptor<S, T>> boolean registerItemWithTarget(
Map<DexType, Set<T>> seen, T item) {
- DexType holder = item.getHolder().toBaseType(appInfo.dexItemFactory);
+ assert item.isDexField() || item.isDexMethod();
+ DexType itemHolder =
+ item.isDexField()
+ ? item.asDexField().holder
+ : item.asDexMethod().holder;
+ DexType holder = itemHolder.toBaseType(appInfo.dexItemFactory);
if (!holder.isClassType()) {
return false;
}
markTypeAsLive(holder);
- return seen.computeIfAbsent(item.getHolder(), (ignore) -> Sets.newIdentityHashSet()).add(item);
+ return seen.computeIfAbsent(itemHolder, (ignore) -> Sets.newIdentityHashSet()).add(item);
}
private <S extends DexItem, T extends Descriptor<S, T>> boolean registerItemWithTargetAndContext(
Map<DexType, Set<TargetWithContext<T>>> seen, T item, DexEncodedMethod context) {
- DexType holder = item.getHolder().toBaseType(appInfo.dexItemFactory);
+ assert item.isDexField() || item.isDexMethod();
+ DexType itemHolder =
+ item.isDexField()
+ ? item.asDexField().holder
+ : item.asDexMethod().holder;
+ DexType holder = itemHolder.toBaseType(appInfo.dexItemFactory);
if (!holder.isClassType()) {
return false;
}
markTypeAsLive(holder);
- return seen.computeIfAbsent(item.getHolder(), (ignore) -> new HashSet<>())
+ return seen
+ .computeIfAbsent(itemHolder, (ignore) -> new HashSet<>())
.add(new TargetWithContext<>(item, context));
}
@@ -616,7 +627,7 @@
DexEncodedField encodedField = appInfo.resolveField(field);
if (encodedField != null && encodedField.isProgramField(appInfo)) {
boolean isWrittenOutsideEnclosingStaticInitializer =
- currentMethod.method.holder != encodedField.field.clazz
+ currentMethod.method.holder != encodedField.field.holder
|| !currentMethod.isClassInitializer();
if (isWrittenOutsideEnclosingStaticInitializer) {
staticFieldsWrittenOutsideEnclosingStaticInitializer.add(encodedField.field);
@@ -798,11 +809,11 @@
}
private DexMethod getInvokeSuperTarget(DexMethod method, DexEncodedMethod currentMethod) {
- DexClass methodHolderClass = appInfo.definitionFor(method.getHolder());
+ DexClass methodHolderClass = appInfo.definitionFor(method.holder);
if (methodHolderClass != null && methodHolderClass.isInterface()) {
return method;
}
- DexClass holderClass = appInfo.definitionFor(currentMethod.method.getHolder());
+ DexClass holderClass = appInfo.definitionFor(currentMethod.method.holder);
if (holderClass == null || holderClass.superType == null || holderClass.isInterface()) {
// We do not know better or this call is made from an interface.
return method;
@@ -1157,7 +1168,7 @@
DexField field, KeepReason reason, DexEncodedField encodedField) {
// Mark the type live here, so that the class exists at runtime. Note that this also marks all
// supertypes as live, so even if the field is actually on a supertype, its class will be live.
- markTypeAsLive(field.clazz);
+ markTypeAsLive(field.holder);
markTypeAsLive(field.type);
// Find the actual field.
@@ -1188,7 +1199,7 @@
private void markInstanceFieldAsLive(DexEncodedField field, KeepReason reason) {
assert field != null;
- markTypeAsLive(field.field.clazz);
+ markTypeAsLive(field.field.holder);
markTypeAsLive(field.field.type);
if (Log.ENABLED) {
Log.verbose(getClass(), "Adding instance field `%s` to live set.", field.field);
@@ -1292,13 +1303,13 @@
if (encodedField.accessFlags.isStatic()) {
markStaticFieldAsLive(encodedField.field, reason);
} else {
- if (isInstantiatedOrHasInstantiatedSubtype(encodedField.field.clazz)) {
+ if (isInstantiatedOrHasInstantiatedSubtype(encodedField.field.holder)) {
// We have at least one live subtype, so mark it as live.
markInstanceFieldAsLive(encodedField, reason);
} else {
// Add the field to the reachable set if the type later becomes instantiated.
reachableInstanceFields
- .computeIfAbsent(encodedField.field.clazz, ignore -> newSetWithoutReasonReporter())
+ .computeIfAbsent(encodedField.field.holder, ignore -> newSetWithoutReasonReporter())
.add(encodedField, reason);
}
}
@@ -1623,7 +1634,7 @@
private void markFieldAsKept(DexEncodedField target, KeepReason reason) {
// If this field no longer has a corresponding class, then we have shaken it away before.
- if (appInfo.definitionFor(target.field.clazz) == null) {
+ if (appInfo.definitionFor(target.field.holder) == null) {
return;
}
if (target.accessFlags.isStatic()) {
@@ -1714,12 +1725,12 @@
}
private DexField tryLookupInstanceField(DexField field) {
- DexEncodedField target = appInfo.lookupInstanceTarget(field.clazz, field);
+ DexEncodedField target = appInfo.lookupInstanceTarget(field.holder, field);
return target == null ? null : target.field;
}
private DexField tryLookupStaticField(DexField field) {
- DexEncodedField target = appInfo.lookupStaticTarget(field.clazz, field);
+ DexEncodedField target = appInfo.lookupStaticTarget(field.holder, field);
return target == null ? null : target.field;
}
@@ -1749,7 +1760,7 @@
}
private void markMethodAsKeptWithCompatRule(DexEncodedMethod method) {
- DexClass holderClass = appInfo.definitionFor(method.method.getHolder());
+ DexClass holderClass = appInfo.definitionFor(method.method.holder);
ProguardKeepRule rule =
ProguardConfigurationUtils.buildMethodKeepRule(holderClass, method);
proguardCompatibilityWorkList.add(
@@ -1809,7 +1820,7 @@
!encodedField.accessFlags.isStatic()
&& appInfo.dexItemFactory.atomicFieldUpdaterMethods.isFieldUpdater(invokedMethod);
if (keepClass) {
- DexClass holderClass = appInfo.definitionFor(encodedField.field.getHolder());
+ DexClass holderClass = appInfo.definitionFor(encodedField.field.holder);
markInstantiated(holderClass.type, KeepReason.reflectiveUseIn(method));
}
markFieldAsKept(encodedField, KeepReason.reflectiveUseIn(method));
@@ -2443,9 +2454,11 @@
DexType typeToCheck;
if (item.isDexType()) {
typeToCheck = item.asDexType();
+ } else if (item.isDexMethod()) {
+ typeToCheck = item.asDexMethod().holder;
} else {
- assert item.isDescriptor();
- typeToCheck = item.asDescriptor().getHolder();
+ assert item.isDexField();
+ typeToCheck = item.asDexField().holder;
}
assert !typeSet.contains(typeToCheck);
}
@@ -2487,7 +2500,7 @@
// TODO(b/121354886): Pinned fields should be in `fieldsRead`.
|| isPinned(field)
// Fields in the class that is synthesized by D8/R8 would be used soon.
- || field.getHolder().isD8R8SynthesizedClassType()
+ || field.holder.isD8R8SynthesizedClassType()
// For library classes we don't know whether a field is read.
|| isLibraryField(field);
}
@@ -2497,7 +2510,7 @@
// TODO(b/121354886): Pinned fields should be in `fieldsWritten`.
|| isPinned(field)
// Fields in the class that is synthesized by D8/R8 would be used soon.
- || field.clazz.isD8R8SynthesizedClassType()
+ || field.holder.isD8R8SynthesizedClassType()
// For library classes we don't know whether a field is rewritten.
|| isLibraryField(field);
}
@@ -2508,7 +2521,7 @@
}
private boolean isLibraryField(DexField field) {
- DexClass holder = definitionFor(field.clazz);
+ DexClass holder = definitionFor(field.holder);
return holder == null || holder.isLibraryClass();
}
@@ -2620,7 +2633,7 @@
}
public DexEncodedMethod lookup(Type type, DexMethod target, DexType invocationContext) {
- DexType holder = target.getHolder();
+ DexType holder = target.holder;
if (!holder.isClassType()) {
return null;
}
@@ -2934,7 +2947,7 @@
@Override
public boolean addField(DexField field) {
- DexClass holder = appInfo.definitionFor(field.clazz);
+ DexClass holder = appInfo.definitionFor(field.holder);
if (holder == null) {
return false;
}
@@ -3119,11 +3132,11 @@
return fieldNodes.computeIfAbsent(
context,
f -> {
- DexClass holderDefinition = appInfo.definitionFor(context.getHolder());
+ DexClass holderDefinition = appInfo.definitionFor(context.holder);
return new FieldGraphNode(
holderDefinition != null && holderDefinition.isLibraryClass(),
Reference.field(
- Reference.classFromDescriptor(f.getHolder().toDescriptorString()),
+ Reference.classFromDescriptor(f.holder.toDescriptorString()),
f.name.toString(),
Reference.typeFromDescriptor(f.type.toDescriptorString())));
});
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java b/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
index 71b3d53..07aaecd 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexDirectReferenceTracer.java
@@ -125,7 +125,7 @@
}
protected boolean registerInvoke(DexMethod method) {
- consumer.accept(method.getHolder());
+ consumer.accept(method.holder);
traceMethodDirectDependencies(method, consumer);
return true;
}
@@ -151,7 +151,7 @@
}
protected boolean registerFieldAccess(DexField field) {
- consumer.accept(field.getHolder());
+ consumer.accept(field.holder);
consumer.accept(field.type);
return true;
}
@@ -179,14 +179,14 @@
@Override
public boolean addField(DexField field) {
- consumer.accept(field.getHolder());
+ consumer.accept(field.holder);
consumer.accept(field.type);
return false;
}
@Override
public boolean addMethod(DexMethod method) {
- consumer.accept(method.getHolder());
+ consumer.accept(method.holder);
addProto(method.proto);
return false;
}
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 9f7d021..7e473a7 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -177,7 +177,7 @@
reporter.failIfPendingErrors();
}
- private static enum IdentifierType {
+ private enum IdentifierType {
CLASS_NAME,
ANY
}
@@ -292,7 +292,11 @@
configurationBuilder.setPackagePrefix(parsePackageNameOrEmptyString());
expectClosingQuote(quote);
} else {
- configurationBuilder.setPackagePrefix("");
+ if (hasNextChar('-')) {
+ configurationBuilder.setPackagePrefix("");
+ } else {
+ configurationBuilder.setPackagePrefix(parsePackageNameOrEmptyString());
+ }
}
} else if (acceptString("flattenpackagehierarchy")) {
if (configurationBuilder.getPackageObfuscationMode() == PackageObfuscationMode.REPACKAGE) {
@@ -308,7 +312,11 @@
configurationBuilder.setFlattenPackagePrefix(parsePackageNameOrEmptyString());
expectClosingQuote(quote);
} else {
- configurationBuilder.setFlattenPackagePrefix("");
+ if (hasNextChar('-')) {
+ configurationBuilder.setFlattenPackagePrefix("");
+ } else {
+ configurationBuilder.setFlattenPackagePrefix(parsePackageNameOrEmptyString());
+ }
}
}
} else if (acceptString("overloadaggressively")) {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
index 7dbae8a..39e5e9a 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationUtils.java
@@ -57,7 +57,7 @@
public static ProguardKeepRule buildMethodKeepRule(DexClass clazz, DexEncodedMethod method) {
// TODO(b/122295241): These generated rules should be linked into the graph, eg, the method
// using identified reflection should be the source keeping the target alive.
- assert clazz.type == method.method.getHolder();
+ assert clazz.type == method.method.holder;
ProguardKeepRule.Builder builder = ProguardKeepRule.builder();
builder.setOrigin(proguardCompatOrigin);
builder.setType(ProguardKeepRuleType.KEEP_CLASS_MEMBERS);
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardMemberRuleReturnValue.java b/src/main/java/com/android/tools/r8/shaking/ProguardMemberRuleReturnValue.java
index a1aad20..c8545c7 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardMemberRuleReturnValue.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardMemberRuleReturnValue.java
@@ -122,7 +122,7 @@
}
} else {
assert isField();
- result.append(field.clazz.toSourceString() + '.' + field.name);
+ result.append(field.holder.toSourceString() + '.' + field.name);
}
return result.toString();
}
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index 208fb9c..e1dd681 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.Descriptor;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
@@ -402,14 +401,14 @@
targetClass.fields(
f ->
liveFields.contains(f)
- && appView.graphLense().getOriginalFieldSignature(f.field).getHolder()
+ && appView.graphLense().getOriginalFieldSignature(f.field).holder
== sourceClass.type));
Iterables.addAll(
filteredMembers,
targetClass.methods(
m ->
(liveMethods.contains(m) || targetedMethods.contains(m))
- && appView.graphLense().getOriginalMethodSignature(m.method).getHolder()
+ && appView.graphLense().getOriginalMethodSignature(m.method).holder
== sourceClass.type));
// If the number of member rules to hold is more than live members, we can't make it.
@@ -575,9 +574,9 @@
}
} else if (seed.isDexField()) {
DexField field = seed.asDexField();
- if (include.test(field.clazz)) {
+ if (include.test(field.holder)) {
out.println(
- field.clazz.toSourceString()
+ field.holder.toSourceString()
+ ": "
+ field.type.toSourceString()
+ " "
@@ -906,7 +905,8 @@
if (context instanceof ProguardKeepRule) {
if (item.isDexEncodedMethod()) {
DexEncodedMethod encodedMethod = item.asDexEncodedMethod();
- if (encodedMethod.method.isLambdaDeserializeMethod(appView.dexItemFactory())) {
+ if (options.isGeneratingDex()
+ && encodedMethod.method.isLambdaDeserializeMethod(appView.dexItemFactory())) {
// Don't keep lambda deserialization methods.
return;
}
@@ -915,7 +915,7 @@
if (options.isInterfaceMethodDesugaringEnabled()
&& encodedMethod.hasCode()
&& (encodedMethod.isPrivateMethod() || encodedMethod.isStaticMember())) {
- DexClass holder = appView.definitionFor(encodedMethod.method.getHolder());
+ DexClass holder = appView.definitionFor(encodedMethod.method.holder);
if (holder != null && holder.isInterface()) {
if (rule.isSpecific()) {
options.reporter.warning(
@@ -1197,7 +1197,7 @@
DexField field = reference.asDexField();
DexEncodedField encodedField = appInfo.definitionFor(field);
if (encodedField != null
- && (encodedField.isStatic() || isKeptDirectlyOrIndirectly(field.clazz, appInfo))) {
+ && (encodedField.isStatic() || isKeptDirectlyOrIndirectly(field.holder, appInfo))) {
// TODO(b/121354886): Enable asserts for reads and writes.
/*assert appInfo.fieldsRead.contains(field)
: "Expected kept field `" + field.toSourceString() + "` to be read";
@@ -1270,9 +1270,12 @@
requiredReferencesPerType.putIfAbsent(type, Sets.newIdentityHashSet());
} else {
assert reference.isDexField() || reference.isDexMethod();
- Descriptor<?, ?> descriptor = reference.asDescriptor();
+ DexType holder =
+ reference.isDexField()
+ ? reference.asDexField().holder
+ : reference.asDexMethod().holder;
requiredReferencesPerType
- .computeIfAbsent(descriptor.getHolder(), key -> Sets.newIdentityHashSet())
+ .computeIfAbsent(holder, key -> Sets.newIdentityHashSet())
.add(reference);
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
index 42b7e21..1895a07 100644
--- a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
@@ -31,7 +31,6 @@
import com.google.common.collect.Multiset.Entry;
import com.google.common.collect.Streams;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -192,7 +191,7 @@
}
}
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final MainDexClasses mainDexClasses;
/** The equivalence that should be used for the member buckets in {@link Representative}. */
@@ -207,7 +206,7 @@
private int numberOfMergedClasses = 0;
public StaticClassMerger(
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<AppInfoWithLiveness> appView,
InternalOptions options,
MainDexClasses mainDexClasses) {
this.appView = appView;
@@ -259,14 +258,14 @@
if (appView.appInfo().neverMerge.contains(clazz.type)) {
return MergeGroup.DONT_MERGE;
}
- if (clazz.staticFields().length + clazz.directMethods().size() + clazz.virtualMethods().size()
+ if (clazz.staticFields().size() + clazz.directMethods().size() + clazz.virtualMethods().size()
== 0) {
return MergeGroup.DONT_MERGE;
}
- if (clazz.instanceFields().length > 0) {
+ if (clazz.instanceFields().size() > 0) {
return MergeGroup.DONT_MERGE;
}
- if (Arrays.stream(clazz.staticFields())
+ if (clazz.staticFields().stream()
.anyMatch(field -> appView.appInfo().isPinned(field.field))) {
return MergeGroup.DONT_MERGE;
}
@@ -284,7 +283,7 @@
// TODO(christofferqa): Remove the invariant that the graph lense should not
// modify any methods from the sets alwaysInline and noSideEffects.
|| appView.appInfo().alwaysInline.contains(method.method)
- || appView.appInfo().noSideEffects.keySet().contains(method))) {
+ || appView.appInfo().noSideEffects.keySet().contains(method.method))) {
return MergeGroup.DONT_MERGE;
}
if (clazz.classInitializationMayHaveSideEffects(appView.appInfo())) {
@@ -311,6 +310,7 @@
// Disallow interfaces from being representatives, since interface methods require desugaring.
return !clazz.isInterface();
}
+
private boolean merge(DexProgramClass clazz, MergeGroup group) {
assert satisfiesMergeCriteria(clazz) == group;
assert group != MergeGroup.DONT_MERGE;
@@ -451,15 +451,15 @@
.allMatch(method -> method.accessFlags.isPrivate() || method.accessFlags.isPublic())) {
return false;
}
- if (!Arrays.stream(clazz.staticFields())
- .allMatch(method -> method.accessFlags.isPrivate() || method.accessFlags.isPublic())) {
+ if (!clazz.staticFields().stream()
+ .allMatch(field -> field.accessFlags.isPrivate() || field.accessFlags.isPublic())) {
return false;
}
// Note that a class is only considered a candidate if it has no instance fields and all of its
// virtual methods are private. Therefore, we don't need to consider check if there are any
// package-private or protected instance fields or virtual methods here.
- assert Arrays.stream(clazz.instanceFields()).count() == 0;
+ assert clazz.instanceFields().size() == 0;
assert clazz.virtualMethods().stream().allMatch(method -> method.accessFlags.isPrivate());
// Check that no methods access package-private or protected members.
@@ -485,8 +485,8 @@
}
assert targetClass.accessFlags.isAtLeastAsVisibleAs(sourceClass.accessFlags);
- assert sourceClass.instanceFields().length == 0;
- assert targetClass.instanceFields().length == 0;
+ assert sourceClass.instanceFields().size() == 0;
+ assert targetClass.instanceFields().size() == 0;
numberOfMergedClasses++;
@@ -534,27 +534,31 @@
}
private DexEncodedField[] mergeFields(
- DexEncodedField[] sourceFields, DexEncodedField[] targetFields, DexProgramClass targetClass) {
- DexEncodedField[] result = new DexEncodedField[sourceFields.length + targetFields.length];
+ List<DexEncodedField> sourceFields,
+ List<DexEncodedField> targetFields,
+ DexProgramClass targetClass) {
+ DexEncodedField[] result = new DexEncodedField[sourceFields.size() + targetFields.size()];
// Move all target fields to result.
- System.arraycopy(targetFields, 0, result, 0, targetFields.length);
+ int index = 0;
+ for (DexEncodedField targetField : targetFields) {
+ result[index++] = targetField;
+ }
// Move source fields to result one by one, renaming them if needed.
FieldSignatureEquivalence equivalence = FieldSignatureEquivalence.get();
Set<Wrapper<DexField>> existingFields =
- Arrays.stream(targetFields)
+ targetFields.stream()
.map(targetField -> equivalence.wrap(targetField.field))
.collect(Collectors.toSet());
Predicate<DexField> availableFieldSignatures =
field -> !existingFields.contains(equivalence.wrap(field));
- int i = targetFields.length;
for (DexEncodedField sourceField : sourceFields) {
DexEncodedField sourceFieldAfterMove =
renameFieldIfNeeded(sourceField, targetClass, availableFieldSignatures);
- result[i++] = sourceFieldAfterMove;
+ result[index++] = sourceFieldAfterMove;
DexField originalField =
fieldMapping.inverse().getOrDefault(sourceField.field, sourceField.field);
@@ -563,6 +567,7 @@
existingFields.add(equivalence.wrap(sourceFieldAfterMove.field));
}
+ assert index == result.length;
return result;
}
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 786d026..743e48d 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -21,7 +21,6 @@
import com.android.tools.r8.utils.StringDiagnostic;
import com.google.common.collect.Sets;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -109,8 +108,14 @@
if (reachableVirtualMethods != null) {
clazz.setVirtualMethods(reachableVirtualMethods);
}
- clazz.setInstanceFields(reachableFields(clazz.instanceFields()));
- clazz.setStaticFields(reachableFields(clazz.staticFields()));
+ DexEncodedField[] reachableInstanceFields = reachableFields(clazz.instanceFields());
+ if (reachableInstanceFields != null) {
+ clazz.setInstanceFields(reachableInstanceFields);
+ }
+ DexEncodedField[] reachableStaticFields = reachableFields(clazz.staticFields());
+ if (reachableStaticFields != null) {
+ clazz.setStaticFields(reachableStaticFields);
+ }
clazz.removeInnerClasses(this::isAttributeReferencingPrunedType);
clazz.removeEnclosingMethod(this::isAttributeReferencingPrunedItem);
usagePrinter.visited();
@@ -145,7 +150,7 @@
// Hence, removal of the current InnerClassAttribute too.
return true;
}
- context = enclosingMethod.getHolder();
+ context = enclosingMethod.holder;
}
}
}
@@ -221,36 +226,37 @@
usagePrinter.printUnusedMethod(method);
}
}
- return reachableMethods.toArray(new DexEncodedMethod[reachableMethods.size()]);
+ return reachableMethods.isEmpty()
+ ? DexEncodedMethod.EMPTY_ARRAY
+ : reachableMethods.toArray(DexEncodedMethod.EMPTY_ARRAY);
}
- private DexEncodedField[] reachableFields(DexEncodedField[] fields) {
+ private DexEncodedField[] reachableFields(List<DexEncodedField> fields) {
Predicate<DexField> isReachableOrReferencedField =
field ->
appInfo.liveFields.contains(field)
|| appInfo.isFieldRead(field)
|| appInfo.isFieldWritten(field);
- int firstUnreachable =
- firstUnreachableIndex(Arrays.asList(fields), isReachableOrReferencedField);
+ int firstUnreachable = firstUnreachableIndex(fields, isReachableOrReferencedField);
// Return the original array if all fields are used.
if (firstUnreachable == -1) {
- return fields;
+ return null;
}
if (Log.ENABLED) {
- Log.debug(getClass(), "Removing field: " + fields[firstUnreachable]);
+ Log.debug(getClass(), "Removing field %s.", fields.get(firstUnreachable));
}
- usagePrinter.printUnusedField(fields[firstUnreachable]);
- ArrayList<DexEncodedField> reachableOrReferencedFields = new ArrayList<>(fields.length);
+ usagePrinter.printUnusedField(fields.get(firstUnreachable));
+ ArrayList<DexEncodedField> reachableOrReferencedFields = new ArrayList<>(fields.size());
for (int i = 0; i < firstUnreachable; i++) {
- reachableOrReferencedFields.add(fields[i]);
+ reachableOrReferencedFields.add(fields.get(i));
}
- for (int i = firstUnreachable + 1; i < fields.length; i++) {
- DexEncodedField field = fields[i];
+ for (int i = firstUnreachable + 1; i < fields.size(); i++) {
+ DexEncodedField field = fields.get(i);
if (isReachableOrReferencedField.test(field.field)) {
reachableOrReferencedFields.add(field);
} else {
if (Log.ENABLED) {
- Log.debug(getClass(), "Removing field: " + field);
+ Log.debug(getClass(), "Removing field %s.", field.field);
}
usagePrinter.printUnusedField(field);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 8f8b8c0..6aa1136 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexClass.FieldSetter;
import com.android.tools.r8.graph.DexClass.MethodSetter;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -198,7 +199,7 @@
private final DexApplication application;
private final AppInfoWithLiveness appInfo;
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
private final ExecutorService executorService;
private final GraphLense graphLense;
private final MethodPoolCollection methodPoolCollection;
@@ -227,7 +228,7 @@
public VerticalClassMerger(
DexApplication application,
- AppView<? extends AppInfoWithLiveness> appView,
+ AppView<AppInfoWithLiveness> appView,
ExecutorService executorService,
Timing timing,
MainDexClasses mainDexClasses) {
@@ -312,7 +313,7 @@
} else if (item.isDexField()) {
// Pin the holder and the type of the field.
DexField field = item.asDexField();
- markTypeAsPinned(field.clazz, reason);
+ markTypeAsPinned(field.holder, reason);
markTypeAsPinned(field.type, reason);
} else {
assert item.isDexMethod();
@@ -1255,11 +1256,11 @@
}
private DexEncodedField[] mergeFields(
- DexEncodedField[] sourceFields,
- DexEncodedField[] targetFields,
+ Collection<DexEncodedField> sourceFields,
+ Collection<DexEncodedField> targetFields,
Predicate<DexField> availableFieldSignatures,
Set<DexString> existingFieldNames) {
- DexEncodedField[] result = new DexEncodedField[sourceFields.length + targetFields.length];
+ DexEncodedField[] result = new DexEncodedField[sourceFields.size() + targetFields.size()];
// Add fields from source
int i = 0;
for (DexEncodedField field : sourceFields) {
@@ -1270,21 +1271,10 @@
i++;
}
// Add fields from target.
- System.arraycopy(targetFields, 0, result, i, targetFields.length);
- return result;
- }
-
- private DexEncodedMethod[] mergeMethods(
- Collection<DexEncodedMethod> sourceMethods, List<DexEncodedMethod> targetMethods) {
- DexEncodedMethod[] result = new DexEncodedMethod[sourceMethods.size() + targetMethods.size()];
- // Add methods from source.
- int i = 0;
- for (DexEncodedMethod method : sourceMethods) {
- result[i] = method;
+ for (DexEncodedField field : targetFields) {
+ result[i] = field;
i++;
}
- // Add methods from target.
- System.arraycopy(targetMethods, 0, result, i, targetMethods.size());
return result;
}
@@ -1372,7 +1362,7 @@
private DexEncodedField renameFieldIfNeeded(
DexEncodedField field, Predicate<DexField> availableFieldSignatures) {
DexString oldName = field.field.name;
- DexType oldHolder = field.field.clazz;
+ DexType oldHolder = field.field.holder;
DexField newSignature =
application.dexItemFactory.createField(target.type, field.field.type, oldName);
@@ -1429,8 +1419,8 @@
for (DexProgramClass clazz : appInfo.classes()) {
fixupMethods(clazz.directMethods(), clazz::setDirectMethod);
fixupMethods(clazz.virtualMethods(), clazz::setVirtualMethod);
- clazz.setStaticFields(substituteTypesIn(clazz.staticFields()));
- clazz.setInstanceFields(substituteTypesIn(clazz.instanceFields()));
+ fixupFields(clazz.staticFields(), clazz::setStaticField);
+ fixupFields(clazz.instanceFields(), clazz::setInstanceField);
}
for (SynthesizedBridgeCode synthesizedBridge : synthesizedBridges) {
synthesizedBridge.updateMethodSignatures(this::fixupMethod);
@@ -1457,22 +1447,21 @@
}
}
- private DexEncodedField[] substituteTypesIn(DexEncodedField[] fields) {
+ private void fixupFields(List<DexEncodedField> fields, FieldSetter setter) {
if (fields == null) {
- return null;
+ return;
}
- for (int i = 0; i < fields.length; i++) {
- DexEncodedField encodedField = fields[i];
+ for (int i = 0; i < fields.size(); i++) {
+ DexEncodedField encodedField = fields.get(i);
DexField field = encodedField.field;
DexType newType = fixupType(field.type);
- DexType newHolder = fixupType(field.clazz);
+ DexType newHolder = fixupType(field.holder);
DexField newField = application.dexItemFactory.createField(newHolder, newType, field.name);
if (newField != encodedField.field) {
lense.move(encodedField.field, newField);
- fields[i] = encodedField.toTypeSubstitutedField(newField);
+ setter.setField(i, encodedField.toTypeSubstitutedField(newField));
}
}
- return fields;
}
private DexMethod fixupMethod(DexMethod method) {
@@ -1752,9 +1741,9 @@
private boolean checkFieldReference(DexField field) {
if (!foundIllegalAccess) {
DexType baseType =
- appView.graphLense().lookupType(field.clazz.toBaseType(appView.dexItemFactory()));
+ appView.graphLense().lookupType(field.holder.toBaseType(appView.dexItemFactory()));
if (baseType.isClassType() && baseType.isSamePackage(source.type)) {
- checkTypeReference(field.clazz);
+ checkTypeReference(field.holder);
checkTypeReference(field.type);
DexEncodedField definition = appView.definitionFor(field);
diff --git a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
index c60ba34..277bf8a 100644
--- a/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
+++ b/src/main/java/com/android/tools/r8/utils/LineNumberOptimizer.java
@@ -356,9 +356,9 @@
DexField dexField = dexEncodedField.field;
DexField originalField = graphLense.getOriginalFieldSignature(dexField);
DexString renamedName = namingLens.lookupName(dexField);
- if (renamedName != originalField.name || originalField.clazz != clazz.type) {
+ if (renamedName != originalField.name || originalField.holder != clazz.type) {
FieldSignature originalSignature =
- FieldSignature.fromDexField(originalField, originalField.clazz != clazz.type);
+ FieldSignature.fromDexField(originalField, originalField.holder != clazz.type);
MemberNaming memberNaming = new MemberNaming(originalSignature, renamedName.toString());
onDemandClassNamingBuilder.get().addMemberEntry(memberNaming);
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 3ccdc81..2d08ac1 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -1023,7 +1023,7 @@
return Streams.stream(method.iterateInstructions(instructionSubject -> {
if (instructionSubject.isInvoke()) {
DexMethod invokedMethod = instructionSubject.getMethod();
- return invokedMethod.getHolder().toString().contains(className)
+ return invokedMethod.holder.toString().contains(className)
&& invokedMethod.name.toString().contains(methodName);
}
return false;
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index 5fccb4a..6eea205 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -9,6 +9,7 @@
import java.nio.file.Path;
import java.util.Arrays;
import java.util.Collection;
+import java.util.concurrent.ExecutionException;
public abstract class TestBuilder<RR extends TestRunResult, T extends TestBuilder<RR, T>> {
@@ -34,18 +35,20 @@
}
@Deprecated
- public abstract RR run(String mainClass) throws IOException, CompilationFailedException;
+ public abstract RR run(String mainClass)
+ throws CompilationFailedException, ExecutionException, IOException;
public abstract RR run(TestRuntime runtime, String mainClass)
- throws IOException, CompilationFailedException;
+ throws CompilationFailedException, ExecutionException, IOException;
@Deprecated
- public RR run(Class mainClass) throws IOException, CompilationFailedException {
+ public RR run(Class<?> mainClass)
+ throws CompilationFailedException, ExecutionException, IOException {
return run(mainClass.getTypeName());
}
- public RR run(TestRuntime runtime, Class mainClass)
- throws IOException, CompilationFailedException {
+ public RR run(TestRuntime runtime, Class<?> mainClass)
+ throws CompilationFailedException, ExecutionException, IOException {
return run(runtime, mainClass.getTypeName());
}
diff --git a/src/test/java/com/android/tools/r8/TestCompileResult.java b/src/test/java/com/android/tools/r8/TestCompileResult.java
index 7fcc59a..1c4d7e1 100644
--- a/src/test/java/com/android/tools/r8/TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/TestCompileResult.java
@@ -4,6 +4,8 @@
package com.android.tools.r8;
import static com.android.tools.r8.TestBase.Backend.DEX;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.junit.Assert.assertThat;
import com.android.tools.r8.ClassFileConsumer.ArchiveConsumer;
import com.android.tools.r8.TestBase.Backend;
@@ -15,6 +17,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
@@ -48,33 +51,38 @@
protected abstract RR createRunResult(ProcessResult result);
@Deprecated
- public RR run(Class<?> mainClass) throws IOException {
+ public RR run(Class<?> mainClass) throws ExecutionException, IOException {
return run(mainClass.getTypeName());
}
@Deprecated
- public RR run(String mainClass) throws IOException {
+ public RR run(String mainClass) throws ExecutionException, IOException {
+ ClassSubject mainClassSubject = inspector().clazz(mainClass);
+ assertThat(mainClassSubject, isPresent());
switch (getBackend()) {
case DEX:
- return runArt(null, additionalRunClassPath, mainClass);
+ return runArt(null, additionalRunClassPath, mainClassSubject.getFinalName());
case CF:
- return runJava(null, additionalRunClassPath, mainClass);
+ return runJava(null, additionalRunClassPath, mainClassSubject.getFinalName());
default:
throw new Unreachable();
}
}
- public RR run(TestRuntime runtime, Class<?> mainClass) throws IOException {
+ public RR run(TestRuntime runtime, Class<?> mainClass) throws ExecutionException, IOException {
return run(runtime, mainClass.getTypeName());
}
- public RR run(TestRuntime runtime, String mainClass) throws IOException {
+ public RR run(TestRuntime runtime, String mainClass) throws ExecutionException, IOException {
assert getBackend() == runtime.getBackend();
+ ClassSubject mainClassSubject = inspector().clazz(mainClass);
+ assertThat(mainClassSubject, isPresent());
if (runtime.isDex()) {
- return runArt(runtime.asDex().getVm(), additionalRunClassPath, mainClass);
+ return runArt(
+ runtime.asDex().getVm(), additionalRunClassPath, mainClassSubject.getFinalName());
}
assert runtime.isCf();
- return runJava(runtime, additionalRunClassPath, mainClass);
+ return runJava(runtime, additionalRunClassPath, mainClassSubject.getFinalName());
}
public CR addRunClasspathFiles(Path... classpath) {
diff --git a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
index 8dbc309..c648668 100644
--- a/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestCompilerBuilder.java
@@ -14,6 +14,7 @@
import java.io.PrintStream;
import java.nio.file.Path;
import java.util.Collection;
+import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.function.Supplier;
@@ -85,13 +86,14 @@
}
@Override
- public RR run(String mainClass) throws IOException, CompilationFailedException {
+ public RR run(String mainClass)
+ throws CompilationFailedException, ExecutionException, IOException {
return compile().run(mainClass);
}
@Override
public RR run(TestRuntime runtime, String mainClass)
- throws IOException, CompilationFailedException {
+ throws CompilationFailedException, ExecutionException, IOException {
return compile().run(runtime, mainClass);
}
diff --git a/src/test/java/com/android/tools/r8/TestRunResult.java b/src/test/java/com/android/tools/r8/TestRunResult.java
index e2f4239..f22b23e 100644
--- a/src/test/java/com/android/tools/r8/TestRunResult.java
+++ b/src/test/java/com/android/tools/r8/TestRunResult.java
@@ -83,6 +83,12 @@
return self();
}
+ public RR assertSuccessWithOutputThatMatches(Matcher<String> matcher) {
+ assertSuccess();
+ assertThat(errorMessage("Run stdout incorrect.", matcher.toString()), result.stdout, matcher);
+ return self();
+ }
+
public CodeInspector inspector() throws IOException, ExecutionException {
// Inspection post run implies success. If inspection of an invalid program is needed it should
// be done on the compilation result or on the input.
diff --git a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
index 511f328..5e3e100 100644
--- a/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestShrinkerBuilder.java
@@ -18,7 +18,7 @@
B extends BaseCompilerCommand.Builder<C, B>,
CR extends TestCompileResult<CR, RR>,
RR extends TestRunResult,
- T extends TestCompilerBuilder<C, B, CR, RR, T>>
+ T extends TestShrinkerBuilder<C, B, CR, RR, T>>
extends TestCompilerBuilder<C, B, CR, RR, T> {
protected boolean enableMinification = true;
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java b/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
index 37d3914..3420ad9 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/B77836766.java
@@ -146,7 +146,7 @@
DexCode code = fooInCls2.getMethod().getCode().asDexCode();
checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
InvokeVirtual invoke = (InvokeVirtual) code.instructions[0];
- assertEquals(absSubject.getDexClass().type, invoke.getMethod().getHolder());
+ assertEquals(absSubject.getDexClass().type, invoke.getMethod().holder);
MethodSubject fooInCls1 =
cls1Subject.method("void", "foo", ImmutableList.of("java.lang.String"));
@@ -154,7 +154,7 @@
code = fooInCls1.getMethod().getCode().asDexCode();
checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
invoke = (InvokeVirtual) code.instructions[0];
- assertEquals(absSubject.getDexClass().type, invoke.getMethod().getHolder());
+ assertEquals(absSubject.getDexClass().type, invoke.getMethod().holder);
}
/**
@@ -252,7 +252,7 @@
DexCode code = barInCls2.getMethod().getCode().asDexCode();
checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
InvokeVirtual invoke = (InvokeVirtual) code.instructions[0];
- assertEquals(baseSubject.getDexClass().type, invoke.getMethod().getHolder());
+ assertEquals(baseSubject.getDexClass().type, invoke.getMethod().holder);
MethodSubject fooInCls1 =
cls1Subject.method("void", "foo", ImmutableList.of("java.lang.Integer"));
@@ -260,7 +260,7 @@
code = fooInCls1.getMethod().getCode().asDexCode();
checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
invoke = (InvokeVirtual) code.instructions[0];
- assertEquals(baseSubject.getDexClass().type, invoke.getMethod().getHolder());
+ assertEquals(baseSubject.getDexClass().type, invoke.getMethod().holder);
}
/**
@@ -346,7 +346,7 @@
DexCode code = barInSub.getMethod().getCode().asDexCode();
checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
InvokeVirtual invoke = (InvokeVirtual) code.instructions[0];
- assertEquals(baseSubject.getDexClass().type, invoke.getMethod().getHolder());
+ assertEquals(baseSubject.getDexClass().type, invoke.getMethod().holder);
}
/*
@@ -420,7 +420,7 @@
DexCode code = barInSub.getMethod().getCode().asDexCode();
checkInstructions(code, ImmutableList.of(InvokeVirtual.class, ReturnVoid.class));
InvokeVirtual invoke = (InvokeVirtual) code.instructions[0];
- assertEquals(baseSubject.getDexClass().type, invoke.getMethod().getHolder());
+ assertEquals(baseSubject.getDexClass().type, invoke.getMethod().holder);
}
private AndroidApp runAndVerifyOnJvmAndArt(
diff --git a/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTest.java b/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTest.java
new file mode 100644
index 0000000..4dc81f4
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTest.java
@@ -0,0 +1,60 @@
+// Copyright (c) 2019, 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.cf;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+class KeepDeserializeLambdaMethodTest {
+ static final String LAMBDA_MESSAGE = "[I'm the lambda.]";
+
+ static void invokeLambda(Object o)
+ throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
+ Method runMethod = o.getClass().getMethod("run");
+ runMethod.invoke(o);
+ }
+}
+
+class KeepDeserializeLambdaMethodTestDex extends KeepDeserializeLambdaMethodTest {
+ public static void main(String[] args) throws Exception {
+ Serializable myLambda =
+ (Runnable & Serializable)
+ () -> System.out.println(KeepDeserializeLambdaMethodTest.LAMBDA_MESSAGE);
+ invokeLambda(myLambda);
+ }
+}
+
+class KeepDeserializeLambdaMethodTestCf extends KeepDeserializeLambdaMethodTest {
+
+ public static void main(String[] args) throws Exception {
+ Serializable myLambda = (Runnable & Serializable) () -> System.out.println(LAMBDA_MESSAGE);
+
+ byte[] bytes;
+ {
+ ByteArrayOutputStream byteStream = new ByteArrayOutputStream();
+ ObjectOutputStream out = new ObjectOutputStream(byteStream);
+ out.writeObject(myLambda);
+ out.close();
+ bytes = byteStream.toByteArray();
+ }
+ Object o;
+ {
+ ByteArrayInputStream byteStream = new ByteArrayInputStream(bytes);
+ ObjectInputStream in = new ObjectInputStream(byteStream);
+ o = in.readObject();
+ in.close();
+ }
+ String name = o.getClass().getName();
+ if (!name.contains("KeepDeserializeLambdaMethodTestCf")) {
+ throw new RuntimeException("Unexpected class name " + name);
+ }
+ invokeLambda(o);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTestRunner.java b/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTestRunner.java
new file mode 100644
index 0000000..c2dc7b7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/cf/KeepDeserializeLambdaMethodTestRunner.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2019, 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.cf;
+
+import static org.hamcrest.core.StringContains.containsString;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.R8TestBuilder;
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper.DexVm.Version;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.io.IOException;
+import java.util.concurrent.ExecutionException;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class KeepDeserializeLambdaMethodTestRunner extends TestBase {
+
+ private static final Class TEST_CLASS_CF =
+ com.android.tools.r8.cf.KeepDeserializeLambdaMethodTestCf.class;
+ private static final Class TEST_CLASS_DEX =
+ com.android.tools.r8.cf.KeepDeserializeLambdaMethodTestDex.class;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection params() {
+ return getTestParameters().withCfRuntimes().withDexRuntime(Version.last()).build();
+ }
+
+ private final TestParameters parameters;
+
+ public KeepDeserializeLambdaMethodTestRunner(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testNoTreeShakingCf() throws Exception {
+ test(false);
+ }
+
+ @Test
+ public void testKeepRuleCf() throws Exception {
+ test(true);
+ }
+
+ private void test(boolean keepRule)
+ throws IOException, CompilationFailedException, ExecutionException {
+ Class testClass = parameters.isCfRuntime() ? TEST_CLASS_CF : TEST_CLASS_DEX;
+ R8TestBuilder builder =
+ testForR8Compat(parameters.getBackend())
+ .addProgramClasses(
+ com.android.tools.r8.cf.KeepDeserializeLambdaMethodTest.class, testClass)
+ .apply(parameters::setMinApiForRuntime)
+ .addKeepMainRule(testClass)
+ .noMinification();
+ if (keepRule) {
+ builder.addKeepRules(
+ "-keepclassmembers class * {",
+ "private static synthetic java.lang.Object "
+ + "$deserializeLambda$(java.lang.invoke.SerializedLambda);",
+ "}");
+ } else {
+ builder.noTreeShaking();
+ }
+ R8TestRunResult result =
+ builder
+ .run(parameters.getRuntime(), testClass)
+ .assertSuccessWithOutputThatMatches(
+ containsString(KeepDeserializeLambdaMethodTest.LAMBDA_MESSAGE))
+ .inspect(
+ inspector -> {
+ MethodSubject method =
+ inspector.clazz(testClass).uniqueMethodWithName("$deserializeLambda$");
+ assertEquals(parameters.isCfRuntime(), method.isPresent());
+ });
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java b/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
index e11b957..95e1e76 100644
--- a/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
+++ b/src/test/java/com/android/tools/r8/dex/JumboStringProcessing.java
@@ -159,7 +159,6 @@
null);
MethodAccessFlags flags = MethodAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC, false);
DexEncodedMethod method = new DexEncodedMethod(null, flags, null, null, code);
- new JumboStringRewriter(method, string, factory).rewrite();
- return method.getCode().asDexCode();
+ return new JumboStringRewriter(method, string, factory).rewrite();
}
}
diff --git a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
index df2d769..298ffe1 100644
--- a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
+++ b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
@@ -48,7 +48,6 @@
import java.util.concurrent.ExecutorService;
import org.junit.Assert;
import org.junit.Before;
-import org.junit.Ignore;
import org.junit.Test;
public class SharedClassWritingTest {
@@ -111,7 +110,6 @@
synthesizedFrom);
}
- @Ignore("b/128281550")
@Test
public void manyFilesWithSharedSynthesizedClass() throws ExecutionException, IOException {
diff --git a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
index 0363c3e..263a4c0 100644
--- a/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
+++ b/src/test/java/com/android/tools/r8/graph/TargetLookupTest.java
@@ -155,8 +155,8 @@
DexMethod methodYOnTest =
getMethod(inspector, "Test", "int", "y", ImmutableList.of()).method;
- DexType classTestSuper = methodXOnTestSuper.getHolder();
- DexType classTest = methodYOnTest.getHolder();
+ DexType classTestSuper = methodXOnTestSuper.holder;
+ DexType classTest = methodYOnTest.holder;
DexProto methodXProto = methodXOnTestSuper.proto;
DexString methodXName = methodXOnTestSuper.name;
DexMethod methodXOnTest =
@@ -205,7 +205,7 @@
.createField(factory.createType("LInterface;"), factory.intType, "aField");
assertEquals(aFieldOnInterface,
- appInfo.lookupStaticTarget(aFieldOnSubClass.getHolder(), aFieldOnSubClass).field);
+ appInfo.lookupStaticTarget(aFieldOnSubClass.holder, aFieldOnSubClass).field);
assertEquals("42", runArt(application));
diff --git a/src/test/java/com/android/tools/r8/invalid/DuplicateDefinitionsTest.java b/src/test/java/com/android/tools/r8/invalid/DuplicateDefinitionsTest.java
index 9c9e785..e92e0f3 100644
--- a/src/test/java/com/android/tools/r8/invalid/DuplicateDefinitionsTest.java
+++ b/src/test/java/com/android/tools/r8/invalid/DuplicateDefinitionsTest.java
@@ -94,7 +94,7 @@
assertThat(clazz, isPresent());
// Redundant fields have been removed.
- assertEquals(1, clazz.getDexClass().instanceFields().length);
- assertEquals(1, clazz.getDexClass().staticFields().length);
+ assertEquals(1, clazz.getDexClass().instanceFields().size());
+ assertEquals(1, clazz.getDexClass().staticFields().size());
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/EscapeAnalysisForNameReflectionTest.java b/src/test/java/com/android/tools/r8/ir/analysis/EscapeAnalysisForNameReflectionTest.java
index 53fbe31..caa474d 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/EscapeAnalysisForNameReflectionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/EscapeAnalysisForNameReflectionTest.java
@@ -173,7 +173,7 @@
return getMatchingInstruction(code, instruction -> {
if (instruction.isInvokeVirtual()) {
DexMethod invokedMethod = instruction.asInvokeVirtual().getInvokedMethod();
- return invokedMethod.getHolder().toDescriptorString().equals("Ljava/lang/Class;")
+ return invokedMethod.holder.toDescriptorString().equals("Ljava/lang/Class;")
&& invokedMethod.name.toString().equals("getSimpleName");
}
return false;
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
index c5ac021..54399f9 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/NullabilityTest.java
@@ -11,6 +11,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexType;
@@ -32,7 +33,6 @@
import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterFieldAccess;
import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterInvoke;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
@@ -47,9 +47,9 @@
Class<?> mainClass,
MethodSignature signature,
boolean npeCaught,
- BiConsumer<AppInfoWithLiveness, IRCode> inspector)
+ BiConsumer<AppInfo, IRCode> inspector)
throws Exception {
- AppView<? extends AppInfoWithLiveness> appView = build(mainClass);
+ AppView<? extends AppInfo> appView = build(mainClass);
CodeInspector codeInspector = new CodeInspector(appView.appInfo().app);
MethodSubject fooSubject = codeInspector.clazz(mainClass.getName()).method(signature);
DexEncodedMethod foo = codeInspector.clazz(mainClass.getName()).method(signature).getMethod();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizationTest.java
index a4f9a92..bb2fc3a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizationTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/IdempotentFunctionCallCanonicalizationTest.java
@@ -108,7 +108,7 @@
}
private static boolean isValueOf(DexMethod method, String descriptor) {
- return method.getHolder().toDescriptorString().equals(descriptor)
+ return method.holder.toDescriptorString().equals(descriptor)
&& method.getArity() == 1
&& method.proto.returnType.toDescriptorString().equals(descriptor)
&& method.name.toString().equals("valueOf");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
index 2f5740c..155a1ba 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTest.java
@@ -7,6 +7,7 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.InstancePut;
@@ -19,7 +20,6 @@
import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterInvoke;
import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterNullCheck;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableSet;
@@ -34,7 +34,7 @@
int expectedNumberOfNonNull,
Consumer<IRCode> testAugmentedIRCode)
throws Exception {
- AppView<? extends AppInfoWithLiveness> appView = build(testClass);
+ AppView<? extends AppInfo> appView = build(testClass);
CodeInspector codeInspector = new CodeInspector(appView.appInfo().app);
MethodSubject fooSubject = codeInspector.clazz(testClass.getName()).method(signature);
IRCode irCode = fooSubject.buildIR();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
index e98eeb1..f21113d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullTrackerTestBase.java
@@ -6,44 +6,25 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithSubtyping;
import com.android.tools.r8.graph.AppServices;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.shaking.Enqueuer;
-import com.android.tools.r8.shaking.Enqueuer.AppInfoWithLiveness;
-import com.android.tools.r8.shaking.ProguardClassFilter;
-import com.android.tools.r8.shaking.ProguardKeepRule;
-import com.android.tools.r8.shaking.RootSetBuilder;
-import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
-import com.google.common.collect.ImmutableList;
-import java.util.concurrent.ExecutorService;
public abstract class NonNullTrackerTestBase extends TestBase {
- protected AppView<? extends AppInfoWithLiveness> build(Class<?> mainClass) throws Exception {
+ protected AppView<? extends AppInfo> build(Class<?> mainClass) throws Exception {
Timing timing = new Timing(getClass().getSimpleName());
AndroidApp app = buildAndroidApp(ToolHelper.getClassAsBytes(mainClass));
InternalOptions options = new InternalOptions();
DexApplication dexApplication = new ApplicationReader(app, options, timing).read().toDirect();
- AppView<? extends AppInfoWithSubtyping> appView =
- AppView.createForR8(new AppInfoWithSubtyping(dexApplication), options);
+ AppView<? extends AppInfo> appView =
+ AppView.createForD8(new AppInfoWithSubtyping(dexApplication), options);
appView.setAppServices(AppServices.builder(appView).build());
- ExecutorService executorService = ThreadUtils.getExecutorService(options);
- RootSet rootSet =
- new RootSetBuilder(
- appView,
- dexApplication,
- ImmutableList.of(ProguardKeepRule.defaultKeepAllRule(unused -> {})),
- options)
- .run(executorService);
- Enqueuer enqueuer = new Enqueuer(appView, options, null);
- return AppView.createForR8(
- enqueuer.traceApplication(rootSet, ProguardClassFilter.empty(), executorService, timing),
- options);
+ return appView;
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java
index ad0ae87..15e9729 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/SimplifyIfNotNullTest.java
@@ -6,49 +6,58 @@
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.TestBase;
-import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.code.Format21t;
-import com.android.tools.r8.code.Format22t;
-import com.android.tools.r8.code.Instruction;
-import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.ir.optimize.nonnull.FieldAccessTest;
import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterArrayAccess;
import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterFieldAccess;
import com.android.tools.r8.ir.optimize.nonnull.NonNullAfterInvoke;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
-import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
import com.google.common.collect.ImmutableList;
-import java.util.Arrays;
+import com.google.common.collect.Streams;
import java.util.List;
import org.junit.Test;
public class SimplifyIfNotNullTest extends TestBase {
- private static boolean isIf(Instruction instruction) {
- return instruction instanceof Format21t || instruction instanceof Format22t;
- }
- private void buildAndTest(Class<?> testClass, List<MethodSignature> signatures) throws Exception {
- AndroidApp app = buildAndroidApp(ToolHelper.getClassAsBytes(testClass));
- AndroidApp r8Result = compileWithR8(app,
- "-keep class " + testClass.getCanonicalName() + " { *; }");
- CodeInspector codeInspector = new CodeInspector(r8Result);
+ private void verifyAbsenceOfIf(
+ CodeInspector codeInspector, Class<?> testClass, List<MethodSignature> signatures) {
for (MethodSignature signature : signatures) {
- DexEncodedMethod method =
- codeInspector.clazz(testClass.getName()).method(signature).getMethod();
- long count = Arrays.stream(method.getCode().asDexCode().instructions)
- .filter(SimplifyIfNotNullTest::isIf).count();
+ MethodSubject method =
+ codeInspector.clazz(testClass).method(signature);
+ long count = Streams.stream(method.iterateInstructions(InstructionSubject::isIf)).count();
assertEquals(0, count);
}
}
+ private void testD8(Class<?> testClass, List<MethodSignature> signatures) throws Exception {
+ CodeInspector codeInspector =
+ testForD8()
+ .addProgramClasses(testClass)
+ .compile()
+ .inspector();
+ verifyAbsenceOfIf(codeInspector, testClass, signatures);
+ }
+
+ private void testR8(Class<?> testClass, List<MethodSignature> signatures) throws Exception {
+ CodeInspector codeInspector =
+ testForR8(Backend.DEX)
+ .addProgramClasses(testClass)
+ .addKeepRules("-keep class " + testClass.getCanonicalName() + " { *; }")
+ .compile()
+ .inspector();
+ verifyAbsenceOfIf(codeInspector, testClass, signatures);
+ }
+
@Test
public void nonNullAfterSafeInvokes() throws Exception {
MethodSignature foo =
new MethodSignature("foo", "int", new String[]{"java.lang.String"});
MethodSignature bar =
new MethodSignature("bar", "int", new String[]{"java.lang.String"});
- buildAndTest(NonNullAfterInvoke.class, ImmutableList.of(foo, bar));
+ testD8(NonNullAfterInvoke.class, ImmutableList.of(foo, bar));
+ testR8(NonNullAfterInvoke.class, ImmutableList.of(foo, bar));
}
@Test
@@ -57,7 +66,8 @@
new MethodSignature("foo", "int", new String[]{"java.lang.String[]"});
MethodSignature bar =
new MethodSignature("bar", "int", new String[]{"java.lang.String[]"});
- buildAndTest(NonNullAfterArrayAccess.class, ImmutableList.of(foo, bar));
+ testD8(NonNullAfterArrayAccess.class, ImmutableList.of(foo, bar));
+ testR8(NonNullAfterArrayAccess.class, ImmutableList.of(foo, bar));
}
@Test
@@ -68,6 +78,7 @@
new String[]{FieldAccessTest.class.getCanonicalName()});
MethodSignature foo2 = new MethodSignature("foo2", "int",
new String[]{FieldAccessTest.class.getCanonicalName()});
- buildAndTest(NonNullAfterFieldAccess.class, ImmutableList.of(foo, bar, foo2));
+ testD8(NonNullAfterFieldAccess.class, ImmutableList.of(foo, bar, foo2));
+ testR8(NonNullAfterFieldAccess.class, ImmutableList.of(foo, bar, foo2));
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ExtraMethodNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ExtraMethodNullTest.java
index 42b0ce4..3ece2da 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ExtraMethodNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ExtraMethodNullTest.java
@@ -6,16 +6,14 @@
import static org.hamcrest.CoreMatchers.containsString;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
-import java.io.IOException;
import org.junit.Test;
public class ExtraMethodNullTest extends TestBase {
@Test
- public void test() throws IOException, CompilationFailedException {
+ public void test() throws Exception {
testForR8(Backend.DEX)
.addProgramClassesAndInnerClasses(One.class)
.addKeepMainRule(One.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InterfaceRenewalInLoopDebugTestRunner.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InterfaceRenewalInLoopDebugTestRunner.java
index 292a83b..c5c10bd 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InterfaceRenewalInLoopDebugTestRunner.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InterfaceRenewalInLoopDebugTestRunner.java
@@ -88,7 +88,7 @@
}
private static boolean isDevirtualizedCall(DexMethod method) {
- return method.getHolder().toSourceString().equals(IMPL.getTypeName())
+ return method.holder.toSourceString().equals(IMPL.getTypeName())
&& method.getArity() == 0
&& method.proto.returnType.isVoidType()
&& method.name.toString().equals("foo");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java
index ee108a7..3d1709a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b111893131/B111893131.java
@@ -104,7 +104,7 @@
if (instr instanceof InvokeVirtual) {
InvokeVirtual invokeVirtual = (InvokeVirtual) instr;
DexMethod invokedMethod = invokeVirtual.getMethod();
- if (invokedMethod.getHolder().getName().endsWith("StringBuilder")) {
+ if (invokedMethod.holder.getName().endsWith("StringBuilder")) {
assertNotEquals("append", invokedMethod.name.toString());
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b112247415/B112247415.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b112247415/B112247415.java
index 2e6fb4c..e789292 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b112247415/B112247415.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b112247415/B112247415.java
@@ -100,7 +100,7 @@
if (instr instanceof InvokeVirtual) {
InvokeVirtual invokeVirtual = (InvokeVirtual) instr;
DexMethod invokedMethod = invokeVirtual.getMethod();
- if (invokedMethod.getHolder().getName().endsWith("StringBuilder")) {
+ if (invokedMethod.holder.getName().endsWith("StringBuilder")) {
assertNotEquals("append", invokedMethod.name.toString());
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTestBase.java b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTestBase.java
index f19c5b0..979d911 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/reflection/GetNameTestBase.java
@@ -45,7 +45,7 @@
}
static boolean isNameReflection(DexMethod method) {
- return method.getHolder().toDescriptorString().equals(CLASS_DESCRIPTOR)
+ return method.holder.toDescriptorString().equals(CLASS_DESCRIPTOR)
&& method.getArity() == 0
&& method.proto.returnType.toDescriptorString().equals(STRING_DESCRIPTOR)
&& method.name.toString().startsWith("get")
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
index 7b3ed4a..3f4801d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizerTest.java
@@ -279,11 +279,11 @@
return Streams.concat(
filterInstructionKind(code, SgetObject.class)
.map(Instruction::getField)
- .filter(fld -> isTypeOfInterest(fld.clazz))
+ .filter(fld -> isTypeOfInterest(fld.holder))
.map(DexField::toSourceString),
filterInstructionKind(code, SputObject.class)
.map(Instruction::getField)
- .filter(fld -> isTypeOfInterest(fld.clazz))
+ .filter(fld -> isTypeOfInterest(fld.holder))
.map(DexField::toSourceString),
filterInstructionKind(code, InvokeStatic.class)
.map(insn -> (InvokeStatic) insn)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringContentCheckTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringContentCheckTest.java
index 0578b85..5e4e5f1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringContentCheckTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringContentCheckTest.java
@@ -194,7 +194,7 @@
}
private static boolean isStringContentChecker(DexMethod method) {
- return method.getHolder().toDescriptorString().equals(STRING_DESCRIPTOR)
+ return method.holder.toDescriptorString().equals(STRING_DESCRIPTOR)
&& (method.proto.returnType.isBooleanType()
|| method.proto.returnType.isIntType()
|| method.proto.returnType.toDescriptorString().equals(STRING_DESCRIPTOR))
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringIsEmptyTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringIsEmptyTest.java
index 88bf38c..0de9105 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringIsEmptyTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringIsEmptyTest.java
@@ -79,7 +79,7 @@
}
private static boolean isStringIsEmpty(DexMethod method) {
- return method.getHolder().toDescriptorString().equals("Ljava/lang/String;")
+ return method.holder.toDescriptorString().equals("Ljava/lang/String;")
&& method.getArity() == 0
&& method.proto.returnType.isBooleanType()
&& method.name.toString().equals("isEmpty");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringLengthTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringLengthTest.java
index a1709bf..2d1d0a5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringLengthTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringLengthTest.java
@@ -114,7 +114,7 @@
}
private static boolean isStringLength(DexMethod method) {
- return method.getHolder().toDescriptorString().equals("Ljava/lang/String;")
+ return method.holder.toDescriptorString().equals("Ljava/lang/String;")
&& method.getArity() == 0
&& method.proto.returnType.isIntType()
&& method.name.toString().equals("length");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringToStringTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringToStringTest.java
index bd7bb01..60a7c1f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringToStringTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringToStringTest.java
@@ -78,7 +78,7 @@
}
private static boolean isStringToString(DexMethod method) {
- return method.getHolder().toDescriptorString().equals(STRING_DESCRIPTOR)
+ return method.holder.toDescriptorString().equals(STRING_DESCRIPTOR)
&& method.getArity() == 0
&& method.proto.returnType.toDescriptorString().equals(STRING_DESCRIPTOR)
&& method.name.toString().equals("toString");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
index 42d7ab4..f8f5fa4 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/string/StringValueOfTest.java
@@ -148,7 +148,7 @@
}
private static boolean isStringValueOf(DexMethod method) {
- return method.getHolder().toDescriptorString().equals(STRING_DESCRIPTOR)
+ return method.holder.toDescriptorString().equals(STRING_DESCRIPTOR)
&& method.getArity() == 1
&& method.proto.returnType.toDescriptorString().equals(STRING_DESCRIPTOR)
&& method.name.toString().equals("valueOf");
@@ -211,7 +211,7 @@
.addProgramClasses(CLASSES)
.run(MAIN)
.assertSuccessWithOutput(JAVA_OUTPUT);
- test(result, 6, 1, 1);
+ test(result, 5, 1, 1);
}
@Test
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
index 30d90eb7..0df662c 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinClassInlinerTest.java
@@ -209,7 +209,7 @@
filterInstructionKind(code, NewInstance.class)
.map(insn -> ((NewInstance) insn).getType()),
filterInstructionKind(code, SgetObject.class)
- .map(insn -> insn.getField().getHolder())
+ .map(insn -> insn.getField().holder)
)
.filter(isTypeOfInterest)
.map(DexType::toSourceString)
diff --git a/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingTest.java b/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingTest.java
index 0b79b3b..1af095d 100644
--- a/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingTest.java
+++ b/src/test/java/com/android/tools/r8/kotlin/KotlinLambdaMergingTest.java
@@ -248,7 +248,7 @@
private static int getLambdaSingletons(DexClass clazz) {
assertEquals(1, clazz.interfaces.size());
- return clazz.staticFields().length;
+ return clazz.staticFields().size();
}
private static boolean isLambdaOrGroup(DexClass clazz) {
diff --git a/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java b/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java
index 057c751..9aa9a0f 100644
--- a/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IdentifierMinifierTest.java
@@ -302,8 +302,8 @@
}
private static int countRenamedClassIdentifier(
- CodeInspector inspector, DexEncodedField[] fields) {
- return Arrays.stream(fields)
+ CodeInspector inspector, List<DexEncodedField> fields) {
+ return fields.stream()
.filter(encodedField -> encodedField.getStaticValue() instanceof DexValueString)
.reduce(0, (cnt, encodedField) -> {
String cnstString =
diff --git a/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java b/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
index aa2e69d..246ea63 100644
--- a/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
+++ b/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
@@ -73,11 +73,11 @@
boolean metKotlinIntrinsicsNullChecks = false;
while (it.hasNext()) {
DexMethod invokedMethod = it.next().getMethod();
- if (invokedMethod.getHolder().toSourceString().contains("java.net")) {
+ if (invokedMethod.holder.toSourceString().contains("java.net")) {
continue;
}
ClassSubject invokedMethodHolderSubject =
- inspector.clazz(invokedMethod.getHolder().toSourceString());
+ inspector.clazz(invokedMethod.holder.toSourceString());
assertThat(invokedMethodHolderSubject, isPresent());
assertEquals(minification, invokedMethodHolderSubject.isRenamed());
MethodSubject invokedMethodSubject = invokedMethodHolderSubject.method(
diff --git a/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java b/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java
index f599f4d..9ade2f9 100644
--- a/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java
+++ b/src/test/java/com/android/tools/r8/naming/signature/GenericSignatureRenamingTest.java
@@ -4,11 +4,9 @@
package com.android.tools.r8.naming.signature;
-import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.CompilationMode;
import com.android.tools.r8.R8TestBuilder;
import com.android.tools.r8.TestBase;
-import java.io.IOException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
@@ -17,37 +15,37 @@
public class GenericSignatureRenamingTest extends TestBase {
@Test
- public void testJVM() throws IOException, CompilationFailedException {
+ public void testJVM() throws Exception {
testForJvm().addTestClasspath().run(Main.class).assertSuccess();
}
@Test
- public void testR8Dex() throws IOException, CompilationFailedException {
+ public void testR8Dex() throws Exception {
test(testForR8(Backend.DEX));
}
@Test
- public void testR8CompatDex() throws IOException, CompilationFailedException {
+ public void testR8CompatDex() throws Exception {
test(testForR8Compat(Backend.DEX));
}
@Test
- public void testR8DexNoMinify() throws IOException, CompilationFailedException {
+ public void testR8DexNoMinify() throws Exception {
test(testForR8(Backend.DEX).addKeepRules("-dontobfuscate"));
}
@Test
- public void testR8Cf() throws IOException, CompilationFailedException {
+ public void testR8Cf() throws Exception {
test(testForR8(Backend.CF));
}
@Test
- public void testR8CfNoMinify() throws IOException, CompilationFailedException {
+ public void testR8CfNoMinify() throws Exception {
test(testForR8(Backend.CF).addKeepRules("-dontobfuscate"));
}
@Test
- public void testD8() throws IOException, CompilationFailedException {
+ public void testD8() throws Exception {
testForD8()
.addProgramClasses(Main.class)
.addProgramClassesAndInnerClasses(A.class, B.class, CY.class, CYY.class)
@@ -58,7 +56,7 @@
.assertSuccess();
}
- private void test(R8TestBuilder builder) throws IOException, CompilationFailedException {
+ private void test(R8TestBuilder builder) throws Exception {
builder
.addKeepRules("-dontoptimize")
.addKeepRules("-keepattributes InnerClasses,EnclosingMethod,Signature")
diff --git a/src/test/java/com/android/tools/r8/proguard/configuration/RepackagingCompatibilityTest.java b/src/test/java/com/android/tools/r8/proguard/configuration/RepackagingCompatibilityTest.java
new file mode 100644
index 0000000..afaf999
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/proguard/configuration/RepackagingCompatibilityTest.java
@@ -0,0 +1,135 @@
+// Copyright (c) 2019, 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.proguard.configuration;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.startsWith;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeFalse;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestRunResult;
+import com.android.tools.r8.TestShrinkerBuilder;
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackagingCompatibilityTest extends TestBase {
+
+ private enum Quote {
+ SINGLE,
+ DOUBLE,
+ NONE
+ }
+
+ private static final String expectedOutput = StringUtils.lines("Hello world!");
+ private static final Class<?> mainClass = RepackagingCompatabilityTestClass.class;
+
+ private final String directive;
+ private final Quote quote;
+ private final boolean repackageToRoot;
+
+ @Parameters(name = "Directive: {0}, quote: {1}, repackage to root: {2}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of("-flattenpackagehierarchy", "-repackageclasses"),
+ Quote.values(),
+ BooleanUtils.values());
+ }
+
+ public RepackagingCompatibilityTest(String directive, Quote quote, boolean repackageToRoot) {
+ this.directive = directive;
+ this.quote = quote;
+ this.repackageToRoot = repackageToRoot;
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runTest(testForR8(Backend.DEX), "R8");
+ }
+
+ @Test
+ public void testProguard() throws Exception {
+ runTest(testForProguard(), "Proguard");
+ }
+
+ private void runTest(TestShrinkerBuilder<?, ?, ?, ?, ?> builder, String shrinker)
+ throws Exception {
+ assumeFalse(
+ String.format(
+ "Only repackage to root when there are no quotes"
+ + " (repackageToRoot: %s, quote: %s, shrinker: %s)",
+ repackageToRoot, quote, shrinker),
+ repackageToRoot && quote != Quote.NONE);
+
+ TestRunResult<?> result =
+ builder
+ .addProgramClasses(mainClass)
+ .addKeepRules(getKeepRules())
+ .run(mainClass)
+ .assertSuccessWithOutput(expectedOutput);
+
+ ClassSubject testClassSubject = result.inspector().clazz(mainClass);
+ assertThat(testClassSubject, isPresent());
+ if (repackageToRoot) {
+ if (directive.equals("-flattenpackagehierarchy")) {
+ assertThat(testClassSubject.getFinalName(), startsWith("a."));
+ } else if (directive.equals("-repackageclasses")) {
+ assertThat(testClassSubject.getFinalName(), not(containsString(".")));
+ } else {
+ fail();
+ }
+ } else {
+ assertThat(testClassSubject.getFinalName(), startsWith("greeter."));
+ }
+ }
+
+ private List<String> getKeepRules() {
+ return ImmutableList.of(
+ // Keep main(), but allow obfuscation
+ "-keep,allowobfuscation class " + mainClass.getTypeName() + " {",
+ " public static void main(...);",
+ "}",
+ // Ensure main() is not renamed
+ "-keepclassmembernames class " + mainClass.getTypeName() + " {",
+ " public static void main(...);",
+ "}",
+ getRepackagingRule());
+ }
+
+ private String getRepackagingRule() {
+ if (repackageToRoot) {
+ return directive;
+ }
+ switch (quote) {
+ case SINGLE:
+ return directive + " 'greeter'";
+ case DOUBLE:
+ return directive + " \"greeter\"";
+ case NONE:
+ return directive + " greeter";
+ default:
+ throw new Unreachable();
+ }
+ }
+}
+
+class RepackagingCompatabilityTestClass {
+
+ public static void main(String[] args) {
+ System.out.println("Hello world!");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/proguard/configuration/UnusedKeepRuleTest.java b/src/test/java/com/android/tools/r8/proguard/configuration/UnusedKeepRuleTest.java
new file mode 100644
index 0000000..ddc20f2
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/proguard/configuration/UnusedKeepRuleTest.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2019, 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.proguard.configuration;
+
+import com.android.tools.r8.TestBase;
+import org.junit.Test;
+
+public class UnusedKeepRuleTest extends TestBase {
+
+ @Test
+ public void test() throws Exception {
+ testForR8(Backend.DEX)
+ .addKeepRules("-keep class NotPresent")
+ .compile()
+ // TODO(b/128494963): Should print a warning that the keep rule does not match anything.
+ .assertNoMessages();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/shaking/PrintUsageTest.java b/src/test/java/com/android/tools/r8/shaking/PrintUsageTest.java
index e5f3517..1f6a0c0 100644
--- a/src/test/java/com/android/tools/r8/shaking/PrintUsageTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/PrintUsageTest.java
@@ -6,8 +6,6 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.OutputMode;
-import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.shaking.PrintUsageTest.PrintUsageInspector.ClassSubject;
@@ -21,20 +19,16 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
-import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
-import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
import java.util.stream.Stream;
import org.junit.Before;
-import org.junit.Rule;
import org.junit.Test;
-import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
@@ -50,9 +44,6 @@
private final List<String> keepRulesFiles;
private final Consumer<PrintUsageInspector> inspection;
- @Rule
- public TemporaryFolder temp = ToolHelper.getTemporaryFolderForTest();
-
public PrintUsageTest(
Backend backend,
String test,
@@ -68,33 +59,19 @@
@Before
public void runR8andGetPrintUsage() throws Exception {
Path out = temp.getRoot().toPath();
- R8Command.Builder builder =
- ToolHelper.addProguardConfigurationConsumer(
- R8Command.builder(),
- pgConfig -> {
- pgConfig.setPrintUsage(true);
- pgConfig.setPrintUsageFile(out.resolve(test + PRINT_USAGE_FILE_SUFFIX));
- })
- .addProgramFiles(Paths.get(programFile))
- .addProguardConfigurationFiles(ListUtils.map(keepRulesFiles, Paths::get));
-
- if (backend == Backend.DEX) {
- builder
- .setOutput(out, OutputMode.DexIndexed)
- .addLibraryFiles(ToolHelper.getDefaultAndroidJar());
- } else {
- builder.setOutput(out, OutputMode.ClassFile).addLibraryFiles(ToolHelper.getJava8RuntimeJar());
- }
- ToolHelper.runR8(
- builder.build(),
- options -> {
- // Disable inlining to make this test not depend on inlining decisions.
- options.enableInlining = false;
- });
+ testForR8(backend)
+ .addProgramFiles(Paths.get(programFile))
+ .addKeepRuleFiles(ListUtils.map(keepRulesFiles, Paths::get))
+ .addKeepRules(
+ "-printusage " + out.resolve(test + PRINT_USAGE_FILE_SUFFIX)
+ )
+ // Disable inlining to make this test not depend on inlining decisions.
+ .addOptionsModification(o -> o.enableInlining = false)
+ .compile();
}
@Test
- public void printUsageTest() throws IOException, ExecutionException {
+ public void printUsageTest() throws IOException {
Path out = temp.getRoot().toPath();
Path printUsageFile = out.resolve(test + PRINT_USAGE_FILE_SUFFIX);
if (inspection != null) {
@@ -118,20 +95,20 @@
List<Object[]> testCases = new ArrayList<>();
for (Backend backend : Backend.values()) {
- Set<String> usedInspections = new HashSet<>();
- for (String test : tests) {
- File[] keepFiles = new File(ToolHelper.EXAMPLES_DIR + test)
- .listFiles(file -> file.isFile() && file.getName().endsWith(".txt"));
- for (File keepFile : keepFiles) {
- String keepName = keepFile.getName();
- Consumer<PrintUsageInspector> inspection =
- getTestOptionalParameter(inspections, usedInspections, test, keepName);
- if (inspection != null) {
- testCases.add(
- new Object[] {backend, test, ImmutableList.of(keepFile.getPath()), inspection});
+ Set<String> usedInspections = new HashSet<>();
+ for (String test : tests) {
+ File[] keepFiles = new File(ToolHelper.EXAMPLES_DIR + test)
+ .listFiles(file -> file.isFile() && file.getName().endsWith(".txt"));
+ for (File keepFile : keepFiles) {
+ String keepName = keepFile.getName();
+ Consumer<PrintUsageInspector> inspection =
+ getTestOptionalParameter(inspections, usedInspections, test, keepName);
+ if (inspection != null) {
+ testCases.add(
+ new Object[] {backend, test, ImmutableList.of(keepFile.getPath()), inspection});
+ }
}
}
- }
assert usedInspections.size() == inspections.size();
}
return testCases;
@@ -152,6 +129,9 @@
}
private static void inspectShaking1(PrintUsageInspector inspector) {
+ Optional<ClassSubject> shaking1 = inspector.clazz("shaking1.Shaking");
+ assertTrue(shaking1.isPresent());
+ assertTrue(shaking1.get().method("void", "<init>", ImmutableList.of()));
assertTrue(inspector.clazz("shaking1.Unused").isPresent());
assertTrue(inspector.clazz("shaking1.Used").isPresent());
ClassSubject used = inspector.clazz("shaking1.Used").get();
@@ -165,10 +145,10 @@
assertTrue(staticFields.get().field("int", "unused"));
Optional<ClassSubject> subClass1 = inspector.clazz("shaking2.SubClass1");
assertTrue(subClass1.isPresent());
- assertTrue(subClass1.get().method("void", "unusedVirtualMethod", Collections.emptyList()));
+ assertTrue(subClass1.get().method("void", "unusedVirtualMethod", ImmutableList.of()));
Optional<ClassSubject> superClass = inspector.clazz("shaking2.SuperClass");
assertTrue(superClass.isPresent());
- assertTrue(superClass.get().method("void", "unusedStaticMethod", Collections.emptyList()));
+ assertTrue(superClass.get().method("void", "unusedStaticMethod", ImmutableList.of()));
}
private static void inspectShaking4(PrintUsageInspector inspector) {
@@ -188,15 +168,15 @@
assertFalse(superClass.isPresent());
Optional<ClassSubject> subClass = inspector.clazz("shaking9.Subclass");
assertTrue(subClass.isPresent());
- assertTrue(subClass.get().method("void", "aMethod", Collections.emptyList()));
- assertFalse(subClass.get().method("void", "<init>", Collections.emptyList()));
+ assertTrue(subClass.get().method("void", "aMethod", ImmutableList.of()));
+ assertFalse(subClass.get().method("void", "<init>", ImmutableList.of()));
}
private static void inspectShaking12(PrintUsageInspector inspector) {
assertFalse(inspector.clazz("shaking12.PeopleClass").isPresent());
Optional<ClassSubject> animal = inspector.clazz("shaking12.AnimalClass");
assertTrue(animal.isPresent());
- assertTrue(animal.get().method("java.lang.String", "getName", Collections.emptyList()));
+ assertTrue(animal.get().method("java.lang.String", "getName", ImmutableList.of()));
}
static class PrintUsageInspector {
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 2171cc4..394e11a 100644
--- a/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ProguardConfigurationParserTest.java
@@ -453,7 +453,7 @@
assertFalse(rule.getReturnValue().isValueRange());
assertTrue(rule.getReturnValue().isField());
assertFalse(rule.getReturnValue().isNull());
- assertEquals("com.google.C", rule.getReturnValue().getField().clazz.toString());
+ assertEquals("com.google.C", rule.getReturnValue().getField().holder.toString());
assertEquals("int", rule.getReturnValue().getField().type.toString());
assertEquals("X", rule.getReturnValue().getField().name.toString());
matches |= 1 << 4;
@@ -522,7 +522,7 @@
assertFalse(rule.getReturnValue().isValueRange());
assertTrue(rule.getReturnValue().isField());
assertFalse(rule.getReturnValue().isNull());
- assertEquals("com.google.C", rule.getReturnValue().getField().clazz.toString());
+ assertEquals("com.google.C", rule.getReturnValue().getField().holder.toString());
assertEquals("int", rule.getReturnValue().getField().type.toString());
assertEquals("X", rule.getReturnValue().getField().name.toString());
matches |= 1 << 4;
@@ -1314,7 +1314,8 @@
parser.parse(createConfigurationForTesting(ImmutableList.of("-keepattributes xxx,")));
fail();
} catch (AbortException e) {
- assertTrue(handler.errors.get(0).getDiagnosticMessage().contains("Expected list element at "));
+ assertTrue(
+ handler.errors.get(0).getDiagnosticMessage().contains("Expected list element at "));
}
}
@@ -2438,4 +2439,57 @@
assertEquals(ProguardKeepRuleType.KEEP_CLASS_MEMBERS.toString(), rule.typeString());
assertEquals("a.b.c.**,!**d,!**e,!**f,g,h,i", rule.getClassNames().toString());
}
+
+ @Test
+ public void directiveAfterRepackagingRuleTest() {
+ List<PackageObfuscationMode> packageObfuscationModes =
+ ImmutableList.of(PackageObfuscationMode.FLATTEN, PackageObfuscationMode.REPACKAGE);
+ for (PackageObfuscationMode packageObfuscationMode : packageObfuscationModes) {
+ String directive =
+ packageObfuscationMode == PackageObfuscationMode.FLATTEN
+ ? "-flattenpackagehierarchy"
+ : "-repackageclasses";
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ parser.parse(createConfigurationForTesting(ImmutableList.of(directive + " -keep class *")));
+ ProguardConfiguration configuration = parser.getConfig();
+ assertEquals(packageObfuscationMode, configuration.getPackageObfuscationMode());
+ assertEquals("", configuration.getPackagePrefix());
+
+ List<ProguardConfigurationRule> rules = configuration.getRules();
+ assertEquals(1, rules.size());
+
+ ProguardConfigurationRule rule = rules.get(0);
+ assertEquals(ProguardKeepRuleType.KEEP.toString(), rule.typeString());
+ assertEquals("*", rule.getClassNames().toString());
+ }
+ }
+
+ @Test
+ public void arobaseAfterRepackagingRuleTest() throws IOException {
+ Path includeFile = writeTextToTempFile("-keep class *");
+ List<PackageObfuscationMode> packageObfuscationModes =
+ ImmutableList.of(PackageObfuscationMode.FLATTEN, PackageObfuscationMode.REPACKAGE);
+ for (PackageObfuscationMode packageObfuscationMode : packageObfuscationModes) {
+ String directive =
+ packageObfuscationMode == PackageObfuscationMode.FLATTEN
+ ? "-flattenpackagehierarchy"
+ : "-repackageclasses";
+ ProguardConfigurationParser parser =
+ new ProguardConfigurationParser(new DexItemFactory(), reporter);
+ parser.parse(
+ createConfigurationForTesting(
+ ImmutableList.of(directive + " @" + includeFile.toAbsolutePath())));
+ ProguardConfiguration configuration = parser.getConfig();
+ assertEquals(packageObfuscationMode, configuration.getPackageObfuscationMode());
+ assertEquals("", configuration.getPackagePrefix());
+
+ List<ProguardConfigurationRule> rules = configuration.getRules();
+ assertEquals(1, rules.size());
+
+ ProguardConfigurationRule rule = rules.get(0);
+ assertEquals(ProguardKeepRuleType.KEEP.toString(), rule.typeString());
+ assertEquals("*", rule.getClassNames().toString());
+ }
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FieldAccessCfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FieldAccessCfInstructionSubject.java
index 8f14d3b..ae7d420 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FieldAccessCfInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FieldAccessCfInstructionSubject.java
@@ -19,7 +19,7 @@
@Override
public TypeSubject holder() {
- return new TypeSubject(codeInspector, ((CfFieldInstruction) instruction).getField().getHolder());
+ return new TypeSubject(codeInspector, ((CfFieldInstruction) instruction).getField().holder);
}
@Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FieldAccessDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FieldAccessDexInstructionSubject.java
index a3a6cff..361213a 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FieldAccessDexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FieldAccessDexInstructionSubject.java
@@ -19,7 +19,7 @@
@Override
public TypeSubject holder() {
- return new TypeSubject(codeInspector, instruction.getField().getHolder());
+ return new TypeSubject(codeInspector, instruction.getField().holder);
}
@Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index c7b3781..0fb0b30 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -114,12 +114,12 @@
@Override
public void forAllFields(Consumer<FoundFieldSubject> inspection) {
CodeInspector.forAll(
- Arrays.asList(dexClass.staticFields()),
+ dexClass.staticFields(),
(dexField, clazz) -> new FoundFieldSubject(codeInspector, dexField, clazz),
this,
inspection);
CodeInspector.forAll(
- Arrays.asList(dexClass.instanceFields()),
+ dexClass.instanceFields(),
(dexField, clazz) -> new FoundFieldSubject(codeInspector, dexField, clazz),
this,
inspection);
@@ -180,7 +180,7 @@
return dexClass.accessFlags.isAnnotation();
}
- private DexEncodedField findField(DexEncodedField[] fields, DexField dexField) {
+ private DexEncodedField findField(List<DexEncodedField> fields, DexField dexField) {
for (DexEncodedField field : fields) {
if (field.field.equals(dexField)) {
return field;
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/InvokeCfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/InvokeCfInstructionSubject.java
index b307112..268fdb2 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/InvokeCfInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/InvokeCfInstructionSubject.java
@@ -21,7 +21,7 @@
@Override
public TypeSubject holder() {
- return new TypeSubject(codeInspector, invokedMethod().getHolder());
+ return new TypeSubject(codeInspector, invokedMethod().holder);
}
@Override
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/InvokeDexInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/InvokeDexInstructionSubject.java
index 7b5d41c..57a0e71 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/InvokeDexInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/InvokeDexInstructionSubject.java
@@ -20,7 +20,7 @@
@Override
public TypeSubject holder() {
- return new TypeSubject(codeInspector, invokedMethod().getHolder());
+ return new TypeSubject(codeInspector, invokedMethod().holder);
}
@Override
diff --git a/tools/run_on_as_app.py b/tools/run_on_as_app.py
index 1548208..1546389 100755
--- a/tools/run_on_as_app.py
+++ b/tools/run_on_as_app.py
@@ -601,7 +601,8 @@
if options.gradle_flags:
args.extend(options.gradle_flags.split(' '))
- stdout = utils.RunGradlew(args, env_vars=env_vars, quiet=options.quiet)
+ stdout = utils.RunGradlew(args, env_vars=env_vars, quiet=options.quiet,
+ logging=not options.golem)
apk_base_name = (archives_base_name
+ (('-' + app.flavor) if app.flavor else '') + '-release')
@@ -653,7 +654,8 @@
'-Pandroid.enableR8.fullMode=' + str(isR8FullMode(shrinker)).lower()]
env_vars = { 'ANDROID_SERIAL': options.emulator_id }
stdout = \
- utils.RunGradlew(args, env_vars=env_vars, quiet=options.quiet, fail=False)
+ utils.RunGradlew(args, env_vars=env_vars, quiet=options.quiet,
+ fail=False, logging=not options.golem)
xml_test_result_dest = os.path.join(out_dir, 'test_result')
as_utils.MoveXMLTestResultFileTo(
diff --git a/tools/utils.py b/tools/utils.py
index 1432ea9..ec830f2 100644
--- a/tools/utils.py
+++ b/tools/utils.py
@@ -129,7 +129,7 @@
print('')
sys.stdout.write(ProgressLogger.UP)
-def RunCmd(cmd, env_vars=None, quiet=False, fail=True):
+def RunCmd(cmd, env_vars=None, quiet=False, fail=True, logging=True):
PrintCmd(cmd, env=env_vars, quiet=quiet)
env = os.environ.copy()
if env_vars:
@@ -137,14 +137,15 @@
process = subprocess.Popen(
cmd, env=env, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout = []
- logger = ProgressLogger(quiet=quiet)
+ logger = ProgressLogger(quiet=quiet) if logging else None
failed = False
while True:
line = process.stdout.readline()
if line != b'':
stripped = line.rstrip()
stdout.append(stripped)
- logger.log(stripped)
+ if logger:
+ logger.log(stripped)
# TODO(christofferqa): r8 should fail with non-zero exit code.
if ('AssertionError:' in stripped
@@ -153,7 +154,8 @@
or 'Compilation failed' in stripped):
failed = True
else:
- logger.done()
+ if logger:
+ logger.done()
exit_code = process.poll()
if exit_code or failed:
for line in stdout:
@@ -165,7 +167,7 @@
def RunGradlew(
args, clean=True, stacktrace=True, use_daemon=False, env_vars=None,
- quiet=False, fail=True):
+ quiet=False, fail=True, logging=True):
cmd = ['./gradlew']
if clean:
assert 'clean' not in args
@@ -177,7 +179,7 @@
assert '--no-daemon' not in args
cmd.append('--no-daemon')
cmd.extend(args)
- return RunCmd(cmd, env_vars=env_vars, quiet=quiet, fail=fail)
+ return RunCmd(cmd, env_vars=env_vars, quiet=quiet, fail=fail, logging=logging)
def IsWindows():
return defines.IsWindows()