Trace executed methods during startup
Fixes: b/238111450
Change-Id: Ifb427528d1a81dac1f718d347759a4b9152bc6a7
diff --git a/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java b/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java
index eb03451..c71d0d3 100644
--- a/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java
+++ b/src/main/java/com/android/tools/r8/dex/StartupMixedSectionLayoutStrategy.java
@@ -79,7 +79,7 @@
virtualFile.classes().size());
LensCodeRewriterUtils rewriter = new LensCodeRewriterUtils(appView, true);
StartupIndexedItemCollection indexedItemCollection = new StartupIndexedItemCollection();
- for (StartupClass<DexType> startupClass : startupOrderForWriting.getClasses()) {
+ for (StartupClass<DexType, DexMethod> startupClass : startupOrderForWriting.getClasses()) {
assert !startupClass.isSynthetic();
DexProgramClass definition = virtualFileDefinitions.get(startupClass.getReference());
if (definition != null) {
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupOrder.java b/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupOrder.java
index 3566ad1..7bbaba0 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupOrder.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/EmptyStartupOrder.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.experimental.startup;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
@@ -22,7 +23,7 @@
}
@Override
- public Collection<StartupClass<DexType>> getClasses() {
+ public Collection<StartupClass<DexType, DexMethod>> getClasses() {
return Collections.emptyList();
}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/NonEmptyStartupOrder.java b/src/main/java/com/android/tools/r8/experimental/startup/NonEmptyStartupOrder.java
index 673e0de..4122aa0 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/NonEmptyStartupOrder.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/NonEmptyStartupOrder.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
@@ -25,16 +26,16 @@
public class NonEmptyStartupOrder extends StartupOrder {
- private final LinkedHashSet<StartupClass<DexType>> startupClasses;
+ private final LinkedHashSet<StartupClass<DexType, DexMethod>> startupClasses;
// Redundant sets to allow efficient querying without boxing.
private final Set<DexType> nonSyntheticStartupClasses = Sets.newIdentityHashSet();
private final Set<DexType> syntheticStartupClasses = Sets.newIdentityHashSet();
- NonEmptyStartupOrder(LinkedHashSet<StartupClass<DexType>> startupClasses) {
+ NonEmptyStartupOrder(LinkedHashSet<StartupClass<DexType, DexMethod>> startupClasses) {
assert !startupClasses.isEmpty();
this.startupClasses = startupClasses;
- for (StartupClass<DexType> startupClass : startupClasses) {
+ for (StartupClass<DexType, DexMethod> startupClass : startupClasses) {
if (startupClass.isSynthetic()) {
syntheticStartupClasses.add(startupClass.getReference());
} else {
@@ -66,7 +67,7 @@
}
@Override
- public Collection<StartupClass<DexType>> getClasses() {
+ public Collection<StartupClass<DexType, DexMethod>> getClasses() {
return startupClasses;
}
@@ -77,13 +78,13 @@
@Override
public StartupOrder rewrittenWithLens(GraphLens graphLens) {
- LinkedHashSet<StartupClass<DexType>> rewrittenStartupClasses =
+ LinkedHashSet<StartupClass<DexType, DexMethod>> rewrittenStartupClasses =
new LinkedHashSet<>(startupClasses.size());
- for (StartupClass<DexType> startupClass : startupClasses) {
+ for (StartupClass<DexType, DexMethod> startupClass : startupClasses) {
rewrittenStartupClasses.add(
- StartupClass.<DexType>builder()
+ StartupClass.dexBuilder()
.setFlags(startupClass.getFlags())
- .setReference(graphLens.lookupType(startupClass.getReference()))
+ .setClassReference(graphLens.lookupType(startupClass.getReference()))
.build());
}
return createNonEmpty(rewrittenStartupClasses);
@@ -91,7 +92,7 @@
@Override
public StartupOrder toStartupOrderForWriting(AppView<?> appView) {
- LinkedHashSet<StartupClass<DexType>> rewrittenStartupClasses =
+ LinkedHashSet<StartupClass<DexType, DexMethod>> rewrittenStartupClasses =
new LinkedHashSet<>(startupClasses.size());
Map<DexType, List<DexProgramClass>> syntheticContextsToSyntheticClasses =
new IdentityHashMap<>();
@@ -105,7 +106,7 @@
}
}
}
- for (StartupClass<DexType> startupClass : startupClasses) {
+ for (StartupClass<DexType, DexMethod> startupClass : startupClasses) {
addStartupClass(
startupClass, rewrittenStartupClasses, syntheticContextsToSyntheticClasses, appView);
}
@@ -114,8 +115,8 @@
}
private static void addStartupClass(
- StartupClass<DexType> startupClass,
- LinkedHashSet<StartupClass<DexType>> rewrittenStartupClasses,
+ StartupClass<DexType, DexMethod> startupClass,
+ LinkedHashSet<StartupClass<DexType, DexMethod>> rewrittenStartupClasses,
Map<DexType, List<DexProgramClass>> syntheticContextsToSyntheticClasses,
AppView<?> appView) {
if (startupClass.isSynthetic()) {
@@ -131,14 +132,15 @@
}
private static boolean addClass(
- DexProgramClass clazz, LinkedHashSet<StartupClass<DexType>> rewrittenStartupClasses) {
+ DexProgramClass clazz,
+ LinkedHashSet<StartupClass<DexType, DexMethod>> rewrittenStartupClasses) {
return rewrittenStartupClasses.add(
- StartupClass.<DexType>builder().setReference(clazz.getType()).build());
+ StartupClass.dexBuilder().setClassReference(clazz.getType()).build());
}
private static void addClassAndParentClasses(
DexType type,
- LinkedHashSet<StartupClass<DexType>> rewrittenStartupClasses,
+ LinkedHashSet<StartupClass<DexType, DexMethod>> rewrittenStartupClasses,
AppView<?> appView) {
DexProgramClass definition = appView.app().programDefinitionFor(type);
if (definition != null) {
@@ -148,7 +150,7 @@
private static void addClassAndParentClasses(
DexProgramClass clazz,
- LinkedHashSet<StartupClass<DexType>> rewrittenStartupClasses,
+ LinkedHashSet<StartupClass<DexType, DexMethod>> rewrittenStartupClasses,
AppView<?> appView) {
if (addClass(clazz, rewrittenStartupClasses)) {
addParentClasses(clazz, rewrittenStartupClasses, appView);
@@ -157,7 +159,7 @@
private static void addParentClasses(
DexProgramClass clazz,
- LinkedHashSet<StartupClass<DexType>> rewrittenStartupClasses,
+ LinkedHashSet<StartupClass<DexType, DexMethod>> rewrittenStartupClasses,
AppView<?> appView) {
clazz.forEachImmediateSupertype(
supertype -> addClassAndParentClasses(supertype, rewrittenStartupClasses, appView));
@@ -165,12 +167,12 @@
@Override
public StartupOrder withoutPrunedItems(PrunedItems prunedItems, SyntheticItems syntheticItems) {
- LinkedHashSet<StartupClass<DexType>> rewrittenStartupClasses =
+ LinkedHashSet<StartupClass<DexType, DexMethod>> rewrittenStartupClasses =
new LinkedHashSet<>(startupClasses.size());
LazyBox<Set<DexType>> contextsOfLiveSynthetics =
new LazyBox<>(
() -> computeContextsOfLiveSynthetics(prunedItems.getPrunedApp(), syntheticItems));
- for (StartupClass<DexType> startupClass : startupClasses) {
+ for (StartupClass<DexType, DexMethod> startupClass : startupClasses) {
// Only prune non-synthetic classes, since the pruning of a class does not imply that all
// classes synthesized from it have been pruned.
if (startupClass.isSynthetic()) {
@@ -196,7 +198,8 @@
return contextsOfLiveSynthetics;
}
- private StartupOrder createNonEmpty(LinkedHashSet<StartupClass<DexType>> startupClasses) {
+ private StartupOrder createNonEmpty(
+ LinkedHashSet<StartupClass<DexType, DexMethod>> startupClasses) {
if (startupClasses.isEmpty()) {
assert false;
return empty();
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupClass.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupClass.java
index 9338d5f..0f76036 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupClass.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupClass.java
@@ -4,84 +4,47 @@
package com.android.tools.r8.experimental.startup;
-public class StartupClass<T> {
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
- private static final int FLAG_SYNTHETIC = 1;
+// TODO(b/238173796): When updating the compiler to have support for taking a list of startup
+// methods, this class may likely be removed along with the StartupItem class, so that only
+// StartupMethod remains.
+public class StartupClass<C, M> extends StartupItem<C, M, C> {
- private final int flags;
- private final T reference;
-
- public StartupClass(int flags, T reference) {
- this.flags = flags;
- this.reference = reference;
+ public StartupClass(int flags, C reference) {
+ super(flags, reference);
}
- public static <T> Builder<T> builder() {
+ public static <C, M> Builder<C, M> builder() {
return new Builder<>();
}
- public int getFlags() {
- return flags;
- }
-
- public T getReference() {
- return reference;
- }
-
- public boolean isSynthetic() {
- return (flags & FLAG_SYNTHETIC) != 0;
+ public static Builder<DexType, DexMethod> dexBuilder() {
+ return new Builder<>();
}
@Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null || getClass() != obj.getClass()) {
- return false;
- }
- StartupClass<?> startupClass = (StartupClass<?>) obj;
- return flags == startupClass.flags && reference.equals(startupClass.reference);
+ public boolean isStartupClass() {
+ return true;
}
@Override
- public int hashCode() {
- assert flags <= 1;
- return (reference.hashCode() << 1) | flags;
+ public StartupClass<C, M> asStartupClass() {
+ return this;
}
- @Override
- public String toString() {
- StringBuilder builder = new StringBuilder();
- if (isSynthetic()) {
- builder.append('S');
- }
- builder.append(reference);
- return builder.toString();
- }
+ public static class Builder<C, M> extends StartupItem.Builder<C, M, Builder<C, M>> {
- public static class Builder<T> {
-
- private int flags;
- private T reference;
-
- public Builder<T> setFlags(int flags) {
- this.flags = flags;
- return this;
+ @Override
+ public Builder<C, M> setMethodReference(M reference) {
+ throw new Unreachable();
}
- public Builder<T> setReference(T reference) {
- this.reference = reference;
- return this;
- }
-
- public Builder<T> setSynthetic() {
- this.flags |= FLAG_SYNTHETIC;
- return this;
- }
-
- public StartupClass<T> build() {
- return new StartupClass<>(flags, reference);
+ @Override
+ public StartupClass<C, M> build() {
+ return new StartupClass<>(flags, classReference);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupConfiguration.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupConfiguration.java
index 9f16dce..d6da209 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupConfiguration.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupConfiguration.java
@@ -23,13 +23,10 @@
public class StartupConfiguration {
- private final List<StartupClass<DexType>> startupClasses;
- private final List<DexMethod> startupMethods;
+ private final List<StartupClass<DexType, DexMethod>> startupClasses;
- public StartupConfiguration(
- List<StartupClass<DexType>> startupClasses, List<DexMethod> startupMethods) {
+ public StartupConfiguration(List<StartupClass<DexType, DexMethod>> startupClasses) {
this.startupClasses = startupClasses;
- this.startupMethods = startupMethods;
}
public static Builder builder() {
@@ -79,51 +76,66 @@
public static StartupConfiguration createStartupConfigurationFromLines(
DexItemFactory dexItemFactory, Reporter reporter, List<String> startupDescriptors) {
- List<StartupClass<DexType>> startupClasses = new ArrayList<>();
- List<DexMethod> startupMethods = new ArrayList<>();
+ List<StartupClass<DexType, DexMethod>> startupClasses = new ArrayList<>();
for (String startupDescriptor : startupDescriptors) {
if (startupDescriptor.isEmpty()) {
continue;
}
- StartupClass.Builder<DexType> startupClassBuilder = StartupClass.builder();
+ StartupClass.Builder<DexType, DexMethod> startupClassBuilder = StartupClass.builder();
startupDescriptor = parseSyntheticFlag(startupDescriptor, startupClassBuilder);
- int methodNameStartIndex = getMethodNameStartIndex(startupDescriptor);
- if (methodNameStartIndex >= 0) {
- DexMethod startupMethod =
- parseStartupMethodDescriptor(startupDescriptor, methodNameStartIndex, dexItemFactory);
- if (startupMethod != null) {
- startupClasses.add(
- startupClassBuilder.setReference(startupMethod.getHolderType()).build());
- startupMethods.add(startupMethod);
- } else {
- reporter.warning(
- new StringDiagnostic("Invalid descriptor for startup method: " + startupDescriptor));
- }
- } else {
- DexType startupClass = parseStartupClassDescriptor(startupDescriptor, dexItemFactory);
- if (startupClass != null) {
- startupClasses.add(startupClassBuilder.setReference(startupClass).build());
- } else {
- reporter.warning(
- new StringDiagnostic("Invalid descriptor for startup class: " + startupDescriptor));
- }
- }
+ parseStartupClassOrMethod(
+ startupDescriptor,
+ dexItemFactory,
+ startupClass ->
+ startupClasses.add(startupClassBuilder.setClassReference(startupClass).build()),
+ // TODO(b/238173796): Startup methods should be added as startup methods.
+ startupMethod ->
+ startupClasses.add(
+ startupClassBuilder.setClassReference(startupMethod.getHolderType()).build()),
+ actual ->
+ reporter.warning(
+ new StringDiagnostic(
+ "Invalid descriptor for startup class or method: " + actual)));
}
- return new StartupConfiguration(startupClasses, startupMethods);
+ return new StartupConfiguration(startupClasses);
}
public static String parseSyntheticFlag(
- String startupDescriptor, StartupClass.Builder<?> startupClassBuilder) {
+ String startupDescriptor, StartupItem.Builder<?, ?, ?> startupItemBuilder) {
if (!startupDescriptor.isEmpty() && startupDescriptor.charAt(0) == 'S') {
- startupClassBuilder.setSynthetic();
+ startupItemBuilder.setSynthetic();
return startupDescriptor.substring(1);
}
return startupDescriptor;
}
- private static int getMethodNameStartIndex(String startupDescriptor) {
- int arrowIndex = startupDescriptor.indexOf("->");
- return arrowIndex >= 0 ? arrowIndex + 2 : arrowIndex;
+ public static void parseStartupClassOrMethod(
+ String startupDescriptor,
+ DexItemFactory dexItemFactory,
+ Consumer<DexType> startupClassConsumer,
+ Consumer<DexMethod> startupMethodConsumer,
+ Consumer<String> parseErrorHandler) {
+ int arrowStartIndex = getArrowStartIndex(startupDescriptor);
+ if (arrowStartIndex >= 0) {
+ DexMethod startupMethod =
+ parseStartupMethodDescriptor(startupDescriptor, arrowStartIndex, dexItemFactory);
+ if (startupMethod != null) {
+ startupMethodConsumer.accept(startupMethod);
+ } else {
+ parseErrorHandler.accept(startupDescriptor);
+ }
+ } else {
+ DexType startupClass = parseStartupClassDescriptor(startupDescriptor, dexItemFactory);
+ if (startupClass != null) {
+ startupClassConsumer.accept(startupClass);
+ } else {
+ parseErrorHandler.accept(startupDescriptor);
+ }
+ }
+ }
+
+ private static int getArrowStartIndex(String startupDescriptor) {
+ return startupDescriptor.indexOf("->");
}
private static DexType parseStartupClassDescriptor(
@@ -136,13 +148,14 @@
}
private static DexMethod parseStartupMethodDescriptor(
- String startupMethodDescriptor, int methodNameStartIndex, DexItemFactory dexItemFactory) {
- String classDescriptor = startupMethodDescriptor.substring(0, methodNameStartIndex - 2);
+ String startupMethodDescriptor, int arrowStartIndex, DexItemFactory dexItemFactory) {
+ String classDescriptor = startupMethodDescriptor.substring(0, arrowStartIndex);
DexType classType = parseStartupClassDescriptor(classDescriptor, dexItemFactory);
if (classType == null) {
return null;
}
+ int methodNameStartIndex = arrowStartIndex + 2;
String protoWithNameDescriptor = startupMethodDescriptor.substring(methodNameStartIndex);
int methodNameEndIndex = protoWithNameDescriptor.indexOf('(');
if (methodNameEndIndex <= 0) {
@@ -171,28 +184,45 @@
return !startupClasses.isEmpty();
}
- public List<StartupClass<DexType>> getStartupClasses() {
+ public List<StartupClass<DexType, DexMethod>> getStartupClasses() {
return startupClasses;
}
public static class Builder {
- private final ImmutableList.Builder<StartupClass<DexType>> startupClassesBuilder =
+ private final ImmutableList.Builder<StartupClass<DexType, DexMethod>> startupClassesBuilder =
ImmutableList.builder();
- private final ImmutableList.Builder<DexMethod> startupMethodsBuilder = ImmutableList.builder();
- public Builder addStartupClass(StartupClass<DexType> startupClass) {
+ public Builder addStartupItem(StartupItem<DexType, DexMethod, ?> startupItem) {
+ if (startupItem.isStartupClass()) {
+ return addStartupClass(startupItem.asStartupClass());
+ } else {
+ assert startupItem.isStartupMethod();
+ return addStartupMethod(startupItem.asStartupMethod());
+ }
+ }
+
+ public Builder addStartupClass(StartupClass<DexType, DexMethod> startupClass) {
this.startupClassesBuilder.add(startupClass);
return this;
}
+ public Builder addStartupMethod(StartupMethod<DexType, DexMethod> startupMethod) {
+ // TODO(b/238173796): Startup methods should be added as startup methods.
+ return addStartupClass(
+ StartupClass.dexBuilder()
+ .setFlags(startupMethod.getFlags())
+ .setClassReference(startupMethod.getReference().getHolderType())
+ .build());
+ }
+
public Builder apply(Consumer<Builder> consumer) {
consumer.accept(this);
return this;
}
public StartupConfiguration build() {
- return new StartupConfiguration(startupClassesBuilder.build(), startupMethodsBuilder.build());
+ return new StartupConfiguration(startupClassesBuilder.build());
}
}
}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupInstrumentation.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupInstrumentation.java
index 804cbca..0678602 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupInstrumentation.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupInstrumentation.java
@@ -18,7 +18,6 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DexValue.DexValueBoolean;
import com.android.tools.r8.graph.DexValue.DexValueString;
@@ -105,11 +104,11 @@
}
private void instrumentClass(DexProgramClass clazz) {
- ProgramMethod classInitializer = ensureClassInitializer(clazz);
- instrumentClassInitializer(classInitializer);
+ ensureClassInitializer(clazz);
+ clazz.forEachProgramMethod(this::instrumentMethod);
}
- private ProgramMethod ensureClassInitializer(DexProgramClass clazz) {
+ private void ensureClassInitializer(DexProgramClass clazz) {
if (!clazz.hasClassInitializer()) {
ComputedApiLevel computedApiLevel =
appView.apiLevelCompute().computeInitialMinApiLevel(appView.options());
@@ -125,22 +124,22 @@
.setMethod(dexItemFactory.createClassInitializer(clazz.getType()))
.build());
}
- return clazz.getProgramClassInitializer();
}
- private void instrumentClassInitializer(ProgramMethod method) {
- DexString descriptor;
+ private void instrumentMethod(ProgramMethod method) {
DexMethod methodToInvoke;
+ DexMethod methodToPrint;
SyntheticItems syntheticItems = appView.getSyntheticItems();
if (syntheticItems.isSyntheticClass(method.getHolder())) {
Collection<DexType> synthesizingContexts =
syntheticItems.getSynthesizingContextTypes(method.getHolderType());
assert synthesizingContexts.size() == 1;
- descriptor = synthesizingContexts.iterator().next().getDescriptor();
+ DexType synthesizingContext = synthesizingContexts.iterator().next();
methodToInvoke = references.addSyntheticMethod;
+ methodToPrint = method.getReference().withHolder(synthesizingContext, dexItemFactory);
} else {
- descriptor = method.getHolderType().getDescriptor();
methodToInvoke = references.addNonSyntheticMethod;
+ methodToPrint = method.getReference();
}
IRCode code = method.buildIR(appView);
@@ -148,7 +147,8 @@
instructionIterator.positionBeforeNextInstructionThatMatches(not(Instruction::isArgument));
Value descriptorValue =
- instructionIterator.insertConstStringInstruction(appView, code, descriptor);
+ instructionIterator.insertConstStringInstruction(
+ appView, code, dexItemFactory.createString(methodToPrint.toSmaliString()));
instructionIterator.add(
InvokeStatic.builder()
.setMethod(methodToInvoke)
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupItem.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupItem.java
new file mode 100644
index 0000000..ada502c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupItem.java
@@ -0,0 +1,134 @@
+// Copyright (c) 2022, 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.experimental.startup;
+
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import java.util.function.Consumer;
+
+public abstract class StartupItem<C, M, R> {
+
+ private static final int FLAG_SYNTHETIC = 1;
+
+ protected final int flags;
+ protected final R reference;
+
+ public StartupItem(int flags, R reference) {
+ this.flags = flags;
+ this.reference = reference;
+ }
+
+ public boolean isStartupClass() {
+ return false;
+ }
+
+ public StartupClass<C, M> asStartupClass() {
+ return null;
+ }
+
+ public boolean isStartupMethod() {
+ return false;
+ }
+
+ public StartupMethod<C, M> asStartupMethod() {
+ return null;
+ }
+
+ public static <C, M> Builder<C, M, ?> builder() {
+ return new Builder<>();
+ }
+
+ public static Builder<DexType, DexMethod, ?> dexBuilder() {
+ return new Builder<>();
+ }
+
+ public int getFlags() {
+ return flags;
+ }
+
+ public R getReference() {
+ return reference;
+ }
+
+ public boolean isSynthetic() {
+ return (flags & FLAG_SYNTHETIC) != 0;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null || getClass() != obj.getClass()) {
+ return false;
+ }
+ StartupItem<?, ?, ?> startupItem = (StartupItem<?, ?, ?>) obj;
+ return flags == startupItem.flags && reference.equals(startupItem.reference);
+ }
+
+ @Override
+ public int hashCode() {
+ return (reference.hashCode() << 1) | flags;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ if (isSynthetic()) {
+ builder.append('S');
+ }
+ builder.append(reference);
+ return builder.toString();
+ }
+
+ public static class Builder<C, M, B extends Builder<C, M, B>> {
+
+ protected int flags;
+ protected C classReference;
+ protected M methodReference;
+
+ public B applyIf(boolean condition, Consumer<B> thenConsumer, Consumer<B> elseConsumer) {
+ if (condition) {
+ thenConsumer.accept(self());
+ } else {
+ elseConsumer.accept(self());
+ }
+ return self();
+ }
+
+ public B setFlags(int flags) {
+ this.flags = flags;
+ return self();
+ }
+
+ public B setClassReference(C reference) {
+ this.classReference = reference;
+ return self();
+ }
+
+ public B setMethodReference(M reference) {
+ this.methodReference = reference;
+ return self();
+ }
+
+ public B setSynthetic() {
+ this.flags |= FLAG_SYNTHETIC;
+ return self();
+ }
+
+ public StartupItem<C, M, ?> build() {
+ if (classReference != null) {
+ return new StartupClass<>(flags, classReference);
+ } else {
+ assert methodReference != null;
+ return new StartupMethod<>(flags, methodReference);
+ }
+ }
+
+ public B self() {
+ return (B) this;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupMethod.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupMethod.java
new file mode 100644
index 0000000..ded8403
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupMethod.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2022, 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.experimental.startup;
+
+import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.experimental.startup.StartupClass.Builder;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
+
+public class StartupMethod<C, M> extends StartupItem<C, M, M> {
+
+ public StartupMethod(int flags, M reference) {
+ super(flags, reference);
+ }
+
+ public static Builder<ClassReference, MethodReference> referenceBuilder() {
+ return new Builder<>();
+ }
+
+ @Override
+ public boolean isStartupMethod() {
+ return true;
+ }
+
+ @Override
+ public StartupMethod<C, M> asStartupMethod() {
+ return this;
+ }
+
+ public static class Builder<C, M> extends StartupItem.Builder<C, M, Builder<C, M>> {
+
+ @Override
+ public Builder<C, M> setClassReference(C reference) {
+ throw new Unreachable();
+ }
+
+ @Override
+ public StartupMethod<C, M> build() {
+ return new StartupMethod<>(flags, methodReference);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java b/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java
index 5d67d8c..1676991 100644
--- a/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java
+++ b/src/main/java/com/android/tools/r8/experimental/startup/StartupOrder.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.experimental.startup;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.PrunedItems;
@@ -35,7 +36,7 @@
public abstract boolean contains(DexType type, SyntheticItems syntheticItems);
- public abstract Collection<StartupClass<DexType>> getClasses();
+ public abstract Collection<StartupClass<DexType, DexMethod>> getClasses();
public abstract boolean isEmpty();
diff --git a/src/main/java/com/android/tools/r8/startup/generated/InstrumentationServerImplFactory.java b/src/main/java/com/android/tools/r8/startup/generated/InstrumentationServerImplFactory.java
index 31c7d4c..e5af39a 100644
--- a/src/main/java/com/android/tools/r8/startup/generated/InstrumentationServerImplFactory.java
+++ b/src/main/java/com/android/tools/r8/startup/generated/InstrumentationServerImplFactory.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.ProgramResource.Kind;
import com.android.tools.r8.androidapi.ComputedApiLevel;
import com.android.tools.r8.cf.CfVersion;
+import com.android.tools.r8.cf.code.CfCheckCast;
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfConstString;
import com.android.tools.r8.cf.code.CfFrame;
@@ -21,6 +22,7 @@
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfLabel;
import com.android.tools.r8.cf.code.CfLoad;
+import com.android.tools.r8.cf.code.CfMonitor;
import com.android.tools.r8.cf.code.CfNew;
import com.android.tools.r8.cf.code.CfReturn;
import com.android.tools.r8.cf.code.CfReturnVoid;
@@ -47,6 +49,7 @@
import com.android.tools.r8.graph.MethodCollection.MethodCollectionFactory;
import com.android.tools.r8.graph.NestHostClassAttribute;
import com.android.tools.r8.ir.code.If;
+import com.android.tools.r8.ir.code.Monitor;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.origin.Origin;
import com.google.common.collect.ImmutableList;
@@ -87,8 +90,8 @@
dexItemFactory.createField(
dexItemFactory.createType(
"Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
- dexItemFactory.createType("Ljava/lang/StringBuilder;"),
- dexItemFactory.createString("builder")))
+ dexItemFactory.createType("Ljava/util/LinkedHashSet;"),
+ dexItemFactory.createString("lines")))
.setAccessFlags(FieldAccessFlags.fromCfAccessFlags(18))
.setApiLevel(ComputedApiLevel.unknown())
.build()
@@ -192,7 +195,7 @@
.setCode(method -> createCfCode4_addSyntheticMethod(dexItemFactory, method))
.build(),
DexEncodedMethod.syntheticBuilder()
- .setAccessFlags(MethodAccessFlags.fromCfAccessFlags(34, false))
+ .setAccessFlags(MethodAccessFlags.fromCfAccessFlags(2, false))
.setApiLevelForCode(ComputedApiLevel.unknown())
.setApiLevelForDefinition(ComputedApiLevel.unknown())
.setClassFileVersion(CfVersion.V1_8)
@@ -240,7 +243,7 @@
private static DexEncodedMethod[] createVirtualMethods(DexItemFactory dexItemFactory) {
return new DexEncodedMethod[] {
DexEncodedMethod.syntheticBuilder()
- .setAccessFlags(MethodAccessFlags.fromCfAccessFlags(33, false))
+ .setAccessFlags(MethodAccessFlags.fromCfAccessFlags(1, false))
.setApiLevelForCode(ComputedApiLevel.unknown())
.setApiLevelForDefinition(ComputedApiLevel.unknown())
.setClassFileVersion(CfVersion.V1_8)
@@ -305,20 +308,20 @@
false),
label1,
new CfLoad(ValueType.OBJECT, 0),
- new CfNew(factory.stringBuilderType),
+ new CfNew(factory.createType("Ljava/util/LinkedHashSet;")),
new CfStackInstruction(CfStackInstruction.Opcode.Dup),
new CfInvoke(
183,
factory.createMethod(
- factory.stringBuilderType,
+ factory.createType("Ljava/util/LinkedHashSet;"),
factory.createProto(factory.voidType),
factory.createString("<init>")),
false),
new CfInstanceFieldWrite(
factory.createField(
factory.createType("Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
- factory.stringBuilderType,
- factory.createString("builder"))),
+ factory.createType("Ljava/util/LinkedHashSet;"),
+ factory.createString("lines"))),
label2,
new CfReturnVoid(),
label3),
@@ -332,30 +335,84 @@
CfLabel label2 = new CfLabel();
CfLabel label3 = new CfLabel();
CfLabel label4 = new CfLabel();
+ CfLabel label5 = new CfLabel();
+ CfLabel label6 = new CfLabel();
+ CfLabel label7 = new CfLabel();
+ CfLabel label8 = new CfLabel();
+ CfLabel label9 = new CfLabel();
+ CfLabel label10 = new CfLabel();
+ CfLabel label11 = new CfLabel();
return new CfCode(
method.holder,
2,
- 2,
+ 4,
ImmutableList.of(
label0,
- new CfStaticFieldRead(
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInstanceFieldRead(
factory.createField(
factory.createType("Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
- factory.booleanType,
- factory.createString("writeToLogcat"))),
- new CfIf(If.Type.EQ, ValueType.INT, label2),
+ factory.createType("Ljava/util/LinkedHashSet;"),
+ factory.createString("lines"))),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfStore(ValueType.OBJECT, 2),
+ new CfMonitor(Monitor.Type.ENTER),
label1,
new CfLoad(ValueType.OBJECT, 0),
+ new CfInstanceFieldRead(
+ factory.createField(
+ factory.createType("Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+ factory.createType("Ljava/util/LinkedHashSet;"),
+ factory.createString("lines"))),
new CfLoad(ValueType.OBJECT, 1),
new CfInvoke(
- 183,
+ 182,
factory.createMethod(
- factory.createType("Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
- factory.createProto(factory.voidType, factory.stringType),
- factory.createString("writeToLogcat")),
+ factory.createType("Ljava/util/LinkedHashSet;"),
+ factory.createProto(factory.booleanType, factory.objectType),
+ factory.createString("add")),
false),
- new CfGoto(label3),
+ new CfIf(If.Type.NE, ValueType.INT, label4),
label2,
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfMonitor(Monitor.Type.EXIT),
+ label3,
+ new CfReturnVoid(),
+ label4,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType(
+ "Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
+ FrameType.initializedNonNullReference(factory.stringType),
+ FrameType.initializedNonNullReference(factory.objectType)
+ })),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfMonitor(Monitor.Type.EXIT),
+ label5,
+ new CfGoto(label8),
+ label6,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType(
+ "Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
+ FrameType.initializedNonNullReference(factory.stringType),
+ FrameType.initializedNonNullReference(factory.objectType)
+ }),
+ new ArrayDeque<>(
+ Arrays.asList(FrameType.initializedNonNullReference(factory.throwableType)))),
+ new CfStore(ValueType.OBJECT, 3),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfMonitor(Monitor.Type.EXIT),
+ label7,
+ new CfLoad(ValueType.OBJECT, 3),
+ new CfThrow(),
+ label8,
new CfFrame(
new Int2ObjectAVLTreeMap<>(
new int[] {0, 1},
@@ -365,30 +422,23 @@
"Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
FrameType.initializedNonNullReference(factory.stringType)
})),
- new CfLoad(ValueType.OBJECT, 0),
- new CfInstanceFieldRead(
+ new CfStaticFieldRead(
factory.createField(
factory.createType("Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
- factory.stringBuilderType,
- factory.createString("builder"))),
+ factory.booleanType,
+ factory.createString("writeToLogcat"))),
+ new CfIf(If.Type.EQ, ValueType.INT, label10),
+ label9,
+ new CfLoad(ValueType.OBJECT, 0),
new CfLoad(ValueType.OBJECT, 1),
new CfInvoke(
- 182,
+ 183,
factory.createMethod(
- factory.stringBuilderType,
- factory.createProto(factory.stringBuilderType, factory.stringType),
- factory.createString("append")),
+ factory.createType("Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("writeToLogcat")),
false),
- new CfConstNumber(10, ValueType.INT),
- new CfInvoke(
- 182,
- factory.createMethod(
- factory.stringBuilderType,
- factory.createProto(factory.stringBuilderType, factory.charType),
- factory.createString("append")),
- false),
- new CfStackInstruction(CfStackInstruction.Opcode.Pop),
- label3,
+ label10,
new CfFrame(
new Int2ObjectAVLTreeMap<>(
new int[] {0, 1},
@@ -399,8 +449,14 @@
FrameType.initializedNonNullReference(factory.stringType)
})),
new CfReturnVoid(),
- label4),
- ImmutableList.of(),
+ label11),
+ ImmutableList.of(
+ new CfTryCatch(
+ label1, label3, ImmutableList.of(factory.throwableType), ImmutableList.of(label6)),
+ new CfTryCatch(
+ label4, label5, ImmutableList.of(factory.throwableType), ImmutableList.of(label6)),
+ new CfTryCatch(
+ label6, label7, ImmutableList.of(factory.throwableType), ImmutableList.of(label6))),
ImmutableList.of());
}
@@ -531,102 +587,146 @@
CfLabel label5 = new CfLabel();
CfLabel label6 = new CfLabel();
CfLabel label7 = new CfLabel();
+ CfLabel label8 = new CfLabel();
+ CfLabel label9 = new CfLabel();
+ CfLabel label10 = new CfLabel();
+ CfLabel label11 = new CfLabel();
+ CfLabel label12 = new CfLabel();
+ CfLabel label13 = new CfLabel();
+ CfLabel label14 = new CfLabel();
+ CfLabel label15 = new CfLabel();
+ CfLabel label16 = new CfLabel();
return new CfCode(
method.holder,
- 3,
4,
+ 8,
ImmutableList.of(
label0,
- new CfNew(factory.createType("Ljava/io/FileOutputStream;")),
+ new CfNew(factory.createType("Ljava/io/PrintWriter;")),
new CfStackInstruction(CfStackInstruction.Opcode.Dup),
new CfLoad(ValueType.OBJECT, 1),
+ new CfConstString(factory.createString("UTF-8")),
new CfInvoke(
183,
factory.createMethod(
- factory.createType("Ljava/io/FileOutputStream;"),
- factory.createProto(factory.voidType, factory.createType("Ljava/io/File;")),
+ factory.createType("Ljava/io/PrintWriter;"),
+ factory.createProto(
+ factory.voidType, factory.createType("Ljava/io/File;"), factory.stringType),
factory.createString("<init>")),
false),
new CfStore(ValueType.OBJECT, 2),
label1,
- new CfLoad(ValueType.OBJECT, 2),
new CfLoad(ValueType.OBJECT, 0),
new CfInstanceFieldRead(
factory.createField(
factory.createType("Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
- factory.stringBuilderType,
- factory.createString("builder"))),
- new CfInvoke(
- 182,
- factory.createMethod(
- factory.stringBuilderType,
- factory.createProto(factory.stringType),
- factory.createString("toString")),
- false),
- new CfConstString(factory.createString("UTF-8")),
- new CfInvoke(
- 184,
- factory.createMethod(
- factory.createType("Ljava/nio/charset/Charset;"),
- factory.createProto(
- factory.createType("Ljava/nio/charset/Charset;"), factory.stringType),
- factory.createString("forName")),
- false),
- new CfInvoke(
- 182,
- factory.createMethod(
- factory.stringType,
- factory.createProto(
- factory.byteArrayType, factory.createType("Ljava/nio/charset/Charset;")),
- factory.createString("getBytes")),
- false),
- new CfInvoke(
- 182,
- factory.createMethod(
- factory.createType("Ljava/io/FileOutputStream;"),
- factory.createProto(factory.voidType, factory.byteArrayType),
- factory.createString("write")),
- false),
+ factory.createType("Ljava/util/LinkedHashSet;"),
+ factory.createString("lines"))),
+ new CfStackInstruction(CfStackInstruction.Opcode.Dup),
+ new CfStore(ValueType.OBJECT, 3),
+ new CfMonitor(Monitor.Type.ENTER),
label2,
- new CfLoad(ValueType.OBJECT, 2),
+ new CfLoad(ValueType.OBJECT, 0),
+ new CfInstanceFieldRead(
+ factory.createField(
+ factory.createType("Lcom/android/tools/r8/startup/InstrumentationServerImpl;"),
+ factory.createType("Ljava/util/LinkedHashSet;"),
+ factory.createString("lines"))),
new CfInvoke(
182,
factory.createMethod(
- factory.createType("Ljava/io/FileOutputStream;"),
- factory.createProto(factory.voidType),
- factory.createString("close")),
+ factory.createType("Ljava/util/LinkedHashSet;"),
+ factory.createProto(factory.createType("Ljava/util/Iterator;")),
+ factory.createString("iterator")),
false),
+ new CfStore(ValueType.OBJECT, 4),
label3,
- new CfGoto(label6),
- label4,
new CfFrame(
new Int2ObjectAVLTreeMap<>(
- new int[] {0, 1, 2},
+ new int[] {0, 1, 2, 3, 4},
new FrameType[] {
FrameType.initializedNonNullReference(
factory.createType(
"Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
FrameType.initializedNonNullReference(factory.createType("Ljava/io/File;")),
FrameType.initializedNonNullReference(
- factory.createType("Ljava/io/FileOutputStream;"))
- }),
- new ArrayDeque<>(
- Arrays.asList(FrameType.initializedNonNullReference(factory.throwableType)))),
- new CfStore(ValueType.OBJECT, 3),
+ factory.createType("Ljava/io/PrintWriter;")),
+ FrameType.initializedNonNullReference(factory.objectType),
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/util/Iterator;"))
+ })),
+ new CfLoad(ValueType.OBJECT, 4),
+ new CfInvoke(
+ 185,
+ factory.createMethod(
+ factory.createType("Ljava/util/Iterator;"),
+ factory.createProto(factory.booleanType),
+ factory.createString("hasNext")),
+ true),
+ new CfIf(If.Type.EQ, ValueType.INT, label6),
+ new CfLoad(ValueType.OBJECT, 4),
+ new CfInvoke(
+ 185,
+ factory.createMethod(
+ factory.createType("Ljava/util/Iterator;"),
+ factory.createProto(factory.objectType),
+ factory.createString("next")),
+ true),
+ new CfCheckCast(factory.stringType),
+ new CfStore(ValueType.OBJECT, 5),
+ label4,
new CfLoad(ValueType.OBJECT, 2),
+ new CfLoad(ValueType.OBJECT, 5),
new CfInvoke(
182,
factory.createMethod(
- factory.createType("Ljava/io/FileOutputStream;"),
- factory.createProto(factory.voidType),
- factory.createString("close")),
+ factory.createType("Ljava/io/PrintWriter;"),
+ factory.createProto(factory.voidType, factory.stringType),
+ factory.createString("println")),
false),
label5,
- new CfLoad(ValueType.OBJECT, 3),
- new CfThrow(),
+ new CfGoto(label3),
label6,
new CfFrame(
new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType(
+ "Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
+ FrameType.initializedNonNullReference(factory.createType("Ljava/io/File;")),
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/io/PrintWriter;")),
+ FrameType.initializedNonNullReference(factory.objectType)
+ })),
+ new CfLoad(ValueType.OBJECT, 3),
+ new CfMonitor(Monitor.Type.EXIT),
+ label7,
+ new CfGoto(label10),
+ label8,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2, 3},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType(
+ "Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
+ FrameType.initializedNonNullReference(factory.createType("Ljava/io/File;")),
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/io/PrintWriter;")),
+ FrameType.initializedNonNullReference(factory.objectType)
+ }),
+ new ArrayDeque<>(
+ Arrays.asList(FrameType.initializedNonNullReference(factory.throwableType)))),
+ new CfStore(ValueType.OBJECT, 6),
+ new CfLoad(ValueType.OBJECT, 3),
+ new CfMonitor(Monitor.Type.EXIT),
+ label9,
+ new CfLoad(ValueType.OBJECT, 6),
+ new CfThrow(),
+ label10,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
new int[] {0, 1, 2},
new FrameType[] {
FrameType.initializedNonNullReference(
@@ -634,13 +734,74 @@
"Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
FrameType.initializedNonNullReference(factory.createType("Ljava/io/File;")),
FrameType.initializedNonNullReference(
- factory.createType("Ljava/io/FileOutputStream;"))
+ factory.createType("Ljava/io/PrintWriter;"))
+ })),
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.createType("Ljava/io/PrintWriter;"),
+ factory.createProto(factory.voidType),
+ factory.createString("close")),
+ false),
+ label11,
+ new CfGoto(label15),
+ label12,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType(
+ "Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
+ FrameType.initializedNonNullReference(factory.createType("Ljava/io/File;")),
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/io/PrintWriter;"))
+ }),
+ new ArrayDeque<>(
+ Arrays.asList(FrameType.initializedNonNullReference(factory.throwableType)))),
+ new CfStore(ValueType.OBJECT, 7),
+ label13,
+ new CfLoad(ValueType.OBJECT, 2),
+ new CfInvoke(
+ 182,
+ factory.createMethod(
+ factory.createType("Ljava/io/PrintWriter;"),
+ factory.createProto(factory.voidType),
+ factory.createString("close")),
+ false),
+ label14,
+ new CfLoad(ValueType.OBJECT, 7),
+ new CfThrow(),
+ label15,
+ new CfFrame(
+ new Int2ObjectAVLTreeMap<>(
+ new int[] {0, 1, 2},
+ new FrameType[] {
+ FrameType.initializedNonNullReference(
+ factory.createType(
+ "Lcom/android/tools/r8/startup/InstrumentationServerImpl;")),
+ FrameType.initializedNonNullReference(factory.createType("Ljava/io/File;")),
+ FrameType.initializedNonNullReference(
+ factory.createType("Ljava/io/PrintWriter;"))
})),
new CfReturnVoid(),
- label7),
+ label16),
ImmutableList.of(
new CfTryCatch(
- label1, label2, ImmutableList.of(factory.throwableType), ImmutableList.of(label4))),
+ label2, label7, ImmutableList.of(factory.throwableType), ImmutableList.of(label8)),
+ new CfTryCatch(
+ label8, label9, ImmutableList.of(factory.throwableType), ImmutableList.of(label8)),
+ new CfTryCatch(
+ label1,
+ label10,
+ ImmutableList.of(factory.throwableType),
+ ImmutableList.of(label12)),
+ new CfTryCatch(
+ label12,
+ label13,
+ ImmutableList.of(factory.throwableType),
+ ImmutableList.of(label12))),
ImmutableList.of());
}
diff --git a/src/main/java/com/android/tools/r8/utils/MethodReferenceUtils.java b/src/main/java/com/android/tools/r8/utils/MethodReferenceUtils.java
index 9818d3e..037fafb 100644
--- a/src/main/java/com/android/tools/r8/utils/MethodReferenceUtils.java
+++ b/src/main/java/com/android/tools/r8/utils/MethodReferenceUtils.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.references.TypeReference;
import com.google.common.collect.ImmutableList;
+import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
@@ -55,6 +56,22 @@
return method.getFormalTypes().size() - other.getFormalTypes().size();
};
+ public static MethodReference classConstructor(Class<?> clazz) {
+ return classConstructor(Reference.classFromClass(clazz));
+ }
+
+ public static MethodReference classConstructor(ClassReference type) {
+ return Reference.classConstructor(type);
+ }
+
+ public static MethodReference instanceConstructor(Class<?> clazz) {
+ return instanceConstructor(Reference.classFromClass(clazz));
+ }
+
+ public static MethodReference instanceConstructor(ClassReference type) {
+ return Reference.method(type, "<init>", Collections.emptyList(), null);
+ }
+
public static int compare(MethodReference methodReference, ClassReference other) {
return ClassReferenceUtils.compare(other, methodReference) * -1;
}
diff --git a/src/test/java/com/android/tools/r8/TestParametersBuilder.java b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
index 59d2bc6..cd34cd5 100644
--- a/src/test/java/com/android/tools/r8/TestParametersBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestParametersBuilder.java
@@ -133,6 +133,10 @@
return withDexRuntimeFilter(vm -> true);
}
+ public TestParametersBuilder withDexRuntimesAndAllApiLevels() {
+ return withDexRuntimes().withAllApiLevels();
+ }
+
/** Add specific runtime if available. */
public TestParametersBuilder withDexRuntime(DexVm.Version runtime) {
return withDexRuntimeFilter(vm -> vm == runtime);
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java
index e77e3d9..2a325ad 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/HorizontalClassMergingWithStartupClassesTest.java
@@ -10,7 +10,6 @@
import com.android.tools.r8.experimental.startup.StartupClass;
import com.android.tools.r8.experimental.startup.StartupConfiguration;
import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexType;
import com.google.common.collect.ImmutableList;
import java.util.Collections;
import java.util.List;
@@ -54,8 +53,8 @@
startupClasses.forEach(
startupClass ->
builder.addStartupClass(
- StartupClass.<DexType>builder()
- .setReference(
+ StartupClass.dexBuilder()
+ .setClassReference(
toDexType(startupClass, dexItemFactory))
.build())))
.build());
diff --git a/src/test/java/com/android/tools/r8/startup/InstrumentationServerImpl.java b/src/test/java/com/android/tools/r8/startup/InstrumentationServerImpl.java
index 6896f3f..328b485 100644
--- a/src/test/java/com/android/tools/r8/startup/InstrumentationServerImpl.java
+++ b/src/test/java/com/android/tools/r8/startup/InstrumentationServerImpl.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.startup;
import java.io.File;
-import java.io.FileOutputStream;
import java.io.IOException;
-import java.nio.charset.Charset;
+import java.io.PrintWriter;
+import java.util.LinkedHashSet;
public class InstrumentationServerImpl extends InstrumentationServer {
@@ -17,7 +17,7 @@
private static boolean writeToLogcat;
private static String logcatTag;
- private final StringBuilder builder = new StringBuilder();
+ private final LinkedHashSet<String> lines = new LinkedHashSet<>();
private InstrumentationServerImpl() {}
@@ -33,21 +33,28 @@
getInstance().addLine('S' + descriptor);
}
- private synchronized void addLine(String line) {
+ private void addLine(String line) {
+ synchronized (lines) {
+ if (!lines.add(line)) {
+ return;
+ }
+ }
if (writeToLogcat) {
writeToLogcat(line);
- } else {
- builder.append(line).append('\n');
}
}
@Override
- public synchronized void writeToFile(File file) throws IOException {
- FileOutputStream stream = new FileOutputStream(file);
+ public void writeToFile(File file) throws IOException {
+ PrintWriter writer = new PrintWriter(file, "UTF-8");
try {
- stream.write(builder.toString().getBytes(Charset.forName("UTF-8")));
+ synchronized (lines) {
+ for (String line : lines) {
+ writer.println(line);
+ }
+ }
} finally {
- stream.close();
+ writer.close();
}
}
diff --git a/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java b/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java
index 4419055..d57a5ab 100644
--- a/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java
+++ b/src/test/java/com/android/tools/r8/startup/MinimalStartupDexTest.java
@@ -14,7 +14,6 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.experimental.startup.StartupClass;
import com.android.tools.r8.experimental.startup.StartupConfiguration;
-import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.InstructionSubject;
@@ -53,12 +52,13 @@
.setStartupConfiguration(
StartupConfiguration.builder()
.addStartupClass(
- StartupClass.<DexType>builder()
- .setReference(toDexType(Main.class, options.dexItemFactory()))
+ StartupClass.dexBuilder()
+ .setClassReference(
+ toDexType(Main.class, options.dexItemFactory()))
.build())
.addStartupClass(
- StartupClass.<DexType>builder()
- .setReference(
+ StartupClass.dexBuilder()
+ .setClassReference(
toDexType(AStartupClass.class, options.dexItemFactory()))
.build())
.build()))
diff --git a/src/test/java/com/android/tools/r8/startup/StartupInstrumentationTest.java b/src/test/java/com/android/tools/r8/startup/StartupInstrumentationTest.java
index 1891b6e..a065a8d 100644
--- a/src/test/java/com/android/tools/r8/startup/StartupInstrumentationTest.java
+++ b/src/test/java/com/android/tools/r8/startup/StartupInstrumentationTest.java
@@ -5,17 +5,18 @@
package com.android.tools.r8.startup;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.experimental.startup.StartupClass;
+import com.android.tools.r8.experimental.startup.StartupItem;
+import com.android.tools.r8.experimental.startup.StartupMethod;
import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
-import com.android.tools.r8.startup.StartupSyntheticPlacementTest.Main;
import com.android.tools.r8.startup.utils.StartupTestingUtils;
+import com.android.tools.r8.utils.MethodReferenceUtils;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
@@ -33,13 +34,12 @@
@Parameters(name = "{0}")
public static TestParametersCollection data() {
- return getTestParameters().withAllRuntimesAndApiLevels().build();
+ return getTestParameters().withDexRuntimesAndAllApiLevels().build();
}
@Test
- public void testD8() throws Exception {
- assumeTrue(parameters.isDexRuntime());
- List<StartupClass<ClassReference>> startupList = new ArrayList<>();
+ public void test() throws Exception {
+ List<StartupItem<ClassReference, MethodReference, ?>> startupList = new ArrayList<>();
testForD8(parameters.getBackend())
.addInnerClasses(getClass())
.apply(StartupTestingUtils.enableStartupInstrumentation(parameters))
@@ -48,7 +48,7 @@
.compile()
.addRunClasspathFiles(StartupTestingUtils.getAndroidUtilLog(temp))
.run(parameters.getRuntime(), Main.class)
- .apply(StartupTestingUtils.removeStartupClassesFromStdout(startupList::add))
+ .apply(StartupTestingUtils.removeStartupListFromStdout(startupList::add))
.assertSuccessWithOutputLines(getExpectedOutput());
assertEquals(getExpectedStartupList(), startupList);
}
@@ -57,13 +57,21 @@
return ImmutableList.of("foo");
}
- private List<StartupClass<ClassReference>> getExpectedStartupList() {
+ private List<StartupMethod<ClassReference, MethodReference>> getExpectedStartupList()
+ throws NoSuchMethodException {
return ImmutableList.of(
- StartupClass.<ClassReference>builder()
- .setReference(Reference.classFromClass(Main.class))
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.classConstructor(Main.class))
.build(),
- StartupClass.<ClassReference>builder()
- .setReference(Reference.classFromClass(AStartupClass.class))
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.mainMethod(Main.class))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.classConstructor(AStartupClass.class))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(
+ Reference.methodFromMethod(AStartupClass.class.getDeclaredMethod("foo")))
.build());
}
diff --git a/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java b/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
index ce9a337..41aff80 100644
--- a/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
+++ b/src/test/java/com/android/tools/r8/startup/StartupSyntheticPlacementTest.java
@@ -13,15 +13,18 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.experimental.startup.StartupClass;
+import com.android.tools.r8.experimental.startup.StartupItem;
+import com.android.tools.r8.experimental.startup.StartupMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.startup.utils.MixedSectionLayoutInspector;
import com.android.tools.r8.startup.utils.StartupTestingUtils;
import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.MethodReferenceUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
@@ -57,7 +60,7 @@
@Test
public void test() throws Exception {
- List<StartupClass<ClassReference>> startupList = new ArrayList<>();
+ List<StartupItem<ClassReference, MethodReference, ?>> startupList = new ArrayList<>();
testForD8(parameters.getBackend())
.addInnerClasses(getClass())
.apply(StartupTestingUtils.enableStartupInstrumentation(parameters))
@@ -66,7 +69,7 @@
.compile()
.addRunClasspathFiles(StartupTestingUtils.getAndroidUtilLog(temp))
.run(parameters.getRuntime(), Main.class, Boolean.toString(useLambda))
- .apply(StartupTestingUtils.removeStartupClassesFromStdout(startupList::add))
+ .apply(StartupTestingUtils.removeStartupListFromStdout(startupList::add))
.assertSuccessWithOutputLines(getExpectedOutput());
assertEquals(getExpectedStartupList(), startupList);
@@ -93,30 +96,60 @@
return ImmutableList.of("A", "B", "C");
}
- private List<StartupClass<ClassReference>> getExpectedStartupList() {
- ImmutableList.Builder<StartupClass<ClassReference>> builder = ImmutableList.builder();
+ private List<StartupMethod<ClassReference, MethodReference>> getExpectedStartupList()
+ throws NoSuchMethodException {
+ ImmutableList.Builder<StartupMethod<ClassReference, MethodReference>> builder =
+ ImmutableList.builder();
builder.add(
- StartupClass.<ClassReference>builder()
- .setReference(Reference.classFromClass(Main.class))
- .build());
- builder.add(
- StartupClass.<ClassReference>builder()
- .setReference(Reference.classFromClass(A.class))
- .build());
- builder.add(
- StartupClass.<ClassReference>builder()
- .setReference(Reference.classFromClass(B.class))
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.classConstructor(Main.class))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.mainMethod(Main.class))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.classConstructor(A.class))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(Reference.methodFromMethod(A.class.getDeclaredMethod("a")))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.classConstructor(B.class))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(
+ Reference.methodFromMethod(B.class.getDeclaredMethod("b", boolean.class)))
.build());
if (useLambda) {
builder.add(
- StartupClass.<ClassReference>builder()
- .setReference(Reference.classFromClass(B.class))
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.classConstructor(B.class))
.setSynthetic()
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.instanceConstructor(B.class))
+ .setSynthetic()
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(
+ Reference.method(
+ Reference.classFromClass(B.class),
+ "accept",
+ ImmutableList.of(Reference.classFromClass(Object.class)),
+ null))
+ .setSynthetic()
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(
+ Reference.methodFromMethod(B.class.getDeclaredMethod("lambda$b$0", Object.class)))
.build());
}
builder.add(
- StartupClass.<ClassReference>builder()
- .setReference(Reference.classFromClass(C.class))
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.classConstructor(C.class))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(Reference.methodFromMethod(C.class.getDeclaredMethod("c")))
.build());
return builder.build();
}
diff --git a/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java b/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java
index 83c581c..0567f4b 100644
--- a/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java
+++ b/src/test/java/com/android/tools/r8/startup/StartupSyntheticWithoutContextTest.java
@@ -14,19 +14,23 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.experimental.startup.StartupClass;
+import com.android.tools.r8.experimental.startup.StartupItem;
+import com.android.tools.r8.experimental.startup.StartupMethod;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.startup.utils.MixedSectionLayoutInspector;
import com.android.tools.r8.startup.utils.StartupTestingUtils;
import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.BooleanUtils;
+import com.android.tools.r8.utils.MethodReferenceUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Collections;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -53,7 +57,7 @@
@Test
public void test() throws Exception {
- List<StartupClass<ClassReference>> startupList = new ArrayList<>();
+ List<StartupItem<ClassReference, MethodReference, ?>> startupList = new ArrayList<>();
testForD8(parameters.getBackend())
.addInnerClasses(getClass())
.apply(StartupTestingUtils.enableStartupInstrumentation(parameters))
@@ -62,7 +66,7 @@
.compile()
.addRunClasspathFiles(StartupTestingUtils.getAndroidUtilLog(temp))
.run(parameters.getRuntime(), Main.class)
- .apply(StartupTestingUtils.removeStartupClassesFromStdout(startupList::add))
+ .apply(StartupTestingUtils.removeStartupListFromStdout(startupList::add))
.assertSuccessWithOutputLines(getExpectedOutput());
assertEquals(getExpectedStartupList(), startupList);
@@ -89,30 +93,50 @@
return ImmutableList.of("A", "B", "C");
}
- private List<StartupClass<ClassReference>> getExpectedStartupList() {
- ImmutableList.Builder<StartupClass<ClassReference>> builder = ImmutableList.builder();
- builder.add(
- StartupClass.<ClassReference>builder()
- .setReference(Reference.classFromClass(Main.class))
- .build());
- builder.add(
- StartupClass.<ClassReference>builder()
- .setReference(Reference.classFromClass(A.class))
- .build());
- builder.add(
- StartupClass.<ClassReference>builder()
- .setReference(Reference.classFromClass(B.class))
- .build());
- builder.add(
- StartupClass.<ClassReference>builder()
- .setReference(Reference.classFromClass(B.class))
+ private List<StartupMethod<ClassReference, MethodReference>> getExpectedStartupList()
+ throws NoSuchMethodException {
+ return ImmutableList.of(
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.classConstructor(Main.class))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.mainMethod(Main.class))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.classConstructor(A.class))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(Reference.methodFromMethod(A.class.getDeclaredMethod("a")))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.classConstructor(B.class))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(Reference.methodFromMethod(B.class.getDeclaredMethod("b")))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.classConstructor(B.class))
.setSynthetic()
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.instanceConstructor(B.class))
+ .setSynthetic()
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(
+ Reference.method(
+ Reference.classFromClass(B.class), "run", Collections.emptyList(), null))
+ .setSynthetic()
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(Reference.methodFromMethod(B.class.getDeclaredMethod("lambda$b$0")))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(MethodReferenceUtils.classConstructor(C.class))
+ .build(),
+ StartupMethod.referenceBuilder()
+ .setMethodReference(Reference.methodFromMethod(C.class.getDeclaredMethod("c")))
.build());
- builder.add(
- StartupClass.<ClassReference>builder()
- .setReference(Reference.classFromClass(C.class))
- .build());
- return builder.build();
}
private List<ClassReference> getExpectedClassDataLayout(int virtualFile) {
diff --git a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
index dad4d44..695bb3a 100644
--- a/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
+++ b/src/test/java/com/android/tools/r8/startup/utils/StartupTestingUtils.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.startup.utils;
import static com.android.tools.r8.TestBase.transformer;
+import static org.junit.Assert.fail;
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8TestBuilder;
@@ -13,13 +14,16 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ThrowableConsumer;
-import com.android.tools.r8.experimental.startup.StartupClass;
import com.android.tools.r8.experimental.startup.StartupConfiguration;
+import com.android.tools.r8.experimental.startup.StartupItem;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.references.ClassReference;
-import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.references.MethodReference;
import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.ClassReferenceUtils;
+import com.android.tools.r8.utils.MethodReferenceUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ThrowingConsumer;
import java.io.IOException;
@@ -59,22 +63,31 @@
.writeToZip();
}
- public static ThrowingConsumer<D8TestRunResult, RuntimeException> removeStartupClassesFromStdout(
- Consumer<StartupClass<ClassReference>> startupClassConsumer) {
- return runResult -> removeStartupClassesFromStdout(runResult, startupClassConsumer);
+ public static ThrowingConsumer<D8TestRunResult, RuntimeException> removeStartupListFromStdout(
+ Consumer<StartupItem<ClassReference, MethodReference, ?>> startupItemConsumer) {
+ return runResult -> removeStartupListFromStdout(runResult, startupItemConsumer);
}
- public static void removeStartupClassesFromStdout(
- D8TestRunResult runResult, Consumer<StartupClass<ClassReference>> startupClassConsumer) {
+ public static void removeStartupListFromStdout(
+ D8TestRunResult runResult,
+ Consumer<StartupItem<ClassReference, MethodReference, ?>> startupItemConsumer) {
+ DexItemFactory dexItemFactory = new DexItemFactory();
StringBuilder stdoutBuilder = new StringBuilder();
String startupDescriptorPrefix = "[" + startupInstrumentationTag + "] ";
for (String line : StringUtils.splitLines(runResult.getStdOut(), true)) {
if (line.startsWith(startupDescriptorPrefix)) {
- StartupClass.Builder<ClassReference> startupClassBuilder = StartupClass.builder();
+ StartupItem.Builder<ClassReference, MethodReference, ?> startupItemBuilder =
+ StartupItem.builder();
String message = line.substring(startupDescriptorPrefix.length());
- message = StartupConfiguration.parseSyntheticFlag(message, startupClassBuilder);
- startupClassBuilder.setReference(Reference.classFromDescriptor(message));
- startupClassConsumer.accept(startupClassBuilder.build());
+ message = StartupConfiguration.parseSyntheticFlag(message, startupItemBuilder);
+ StartupConfiguration.parseStartupClassOrMethod(
+ message,
+ dexItemFactory,
+ startupClass -> startupItemBuilder.setClassReference(startupClass.asClassReference()),
+ startupMethod ->
+ startupItemBuilder.setMethodReference(startupMethod.asMethodReference()),
+ error -> fail("Unexpected parse error: " + error));
+ startupItemConsumer.accept(startupItemBuilder.build());
} else {
stdoutBuilder.append(line).append(System.lineSeparator());
}
@@ -83,29 +96,41 @@
}
public static void setStartupConfiguration(
- R8TestBuilder<?> testBuilder, List<StartupClass<ClassReference>> startupClasses) {
+ R8TestBuilder<?> testBuilder,
+ List<StartupItem<ClassReference, MethodReference, ?>> startupItems) {
testBuilder.addOptionsModification(
options -> {
DexItemFactory dexItemFactory = options.dexItemFactory();
- options
- .getStartupOptions()
- .setStartupConfiguration(
- StartupConfiguration.builder()
- .apply(
- builder ->
- startupClasses.forEach(
- startupClass ->
- builder.addStartupClass(
- StartupClass.<DexType>builder()
- .setFlags(startupClass.getFlags())
- .setReference(
- dexItemFactory.createType(
- startupClass.getReference().getDescriptor()))
- .build())))
- .build());
+ StartupConfiguration startupConfiguration =
+ StartupConfiguration.builder()
+ .apply(
+ builder ->
+ startupItems.forEach(
+ startupItem ->
+ builder.addStartupItem(
+ convertStartupItemToDex(startupItem, dexItemFactory))))
+ .build();
+ options.getStartupOptions().setStartupConfiguration(startupConfiguration);
});
}
+ private static StartupItem<DexType, DexMethod, ?> convertStartupItemToDex(
+ StartupItem<ClassReference, MethodReference, ?> startupItem, DexItemFactory dexItemFactory) {
+ return StartupItem.dexBuilder()
+ .applyIf(
+ startupItem.isStartupClass(),
+ builder ->
+ builder.setClassReference(
+ ClassReferenceUtils.toDexType(
+ startupItem.asStartupClass().getReference(), dexItemFactory)),
+ builder ->
+ builder.setMethodReference(
+ MethodReferenceUtils.toDexMethod(
+ startupItem.asStartupMethod().getReference(), dexItemFactory)))
+ .setFlags(startupItem.getFlags())
+ .build();
+ }
+
private static byte[] getTransformedAndroidUtilLog() throws IOException {
return transformer(Log.class).setClassDescriptor("Landroid/util/Log;").transform();
}