Hygienic outlining.
Bug: 158159959
Fixes: 177847090
Change-Id: Ieb0e43bc0da3f0076c69778467f68a3b89080078
diff --git a/src/main/java/com/android/tools/r8/graph/DexType.java b/src/main/java/com/android/tools/r8/graph/DexType.java
index 56f9a92..c488caf 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -19,7 +19,6 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.synthesis.SyntheticNaming;
import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
import com.android.tools.r8.utils.structural.CompareToVisitor;
import com.android.tools.r8.utils.structural.HashingVisitor;
import com.android.tools.r8.utils.structural.StructuralMapping;
@@ -44,6 +43,7 @@
"$r8$twr$utility",
"$-DC",
"$$ServiceLoaderMethods",
+ "com.android.tools.r8.GeneratedOutlineSupport",
"-$$Lambda$");
public final DexString descriptor;
@@ -338,7 +338,6 @@
// Any entry that is removed from here must be added to OLD_SYNTHESIZED_NAMES to ensure that
// newer releases can be used to merge previous builds.
return name.contains(LAMBDA_GROUP_CLASS_NAME_PREFIX) // Could collide.
- || name.contains(OutlineOptions.CLASS_NAME) // Global singleton.
|| name.contains(NestBasedAccessDesugaring.NEST_CONSTRUCTOR_NAME); // Global singleton.
}
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 152d618..db1f69b 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
@@ -20,7 +20,6 @@
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.DexTypeList;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -101,7 +100,6 @@
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
-import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
import com.android.tools.r8.utils.Timing;
@@ -838,9 +836,8 @@
outliner.identifyOutlineSites(code);
},
executorService);
- DexProgramClass outlineClass = outliner.buildOutlinerClass(computeOutlineClassType());
- appView.appInfo().addSynthesizedClass(outlineClass, true);
- optimizeSynthesizedClass(outlineClass, executorService);
+ List<ProgramMethod> outlineMethods = outliner.buildOutlineMethods();
+ optimizeSynthesizedMethods(outlineMethods, executorService);
forEachSelectedOutliningMethod(
methodsSelectedForOutlining,
code -> {
@@ -852,8 +849,7 @@
executorService);
feedback.updateVisibleOptimizationInfo();
assert outliner.checkAllOutlineSitesFoundAgain();
- builder.addSynthesizedClass(outlineClass);
- clearDexMethodCompilationState(outlineClass);
+ outlineMethods.forEach(m -> m.getDefinition().markNotProcessed());
}
timing.end();
}
@@ -1037,27 +1033,11 @@
}
}
- // Find an unused name for the outlining class. When multiple runs produces additional
- // outlining the default outlining class might already be present.
- private DexType computeOutlineClassType() {
- DexType result;
- int count = 0;
- String prefix = appView.options().synthesizedClassPrefix.replace('/', '.');
- do {
- String name =
- prefix + OutlineOptions.CLASS_NAME + (count == 0 ? "" : Integer.toString(count));
- count++;
- result = appView.dexItemFactory().createType(DescriptorUtils.javaTypeToDescriptor(name));
-
- } while (appView.appInfo().definitionForWithoutExistenceAssert(result) != null);
- return result;
- }
-
- public void optimizeSynthesizedClass(
- DexProgramClass clazz, ExecutorService executorService)
+ public void optimizeSynthesizedMethods(
+ List<ProgramMethod> programMethods, ExecutorService executorService)
throws ExecutionException {
// Process the generated class, but don't apply any outlining.
- SortedProgramMethodSet methods = SortedProgramMethodSet.create(clazz::forEachProgramMethod);
+ SortedProgramMethodSet methods = SortedProgramMethodSet.create(programMethods::forEach);
processMethodsConcurrently(methods, executorService);
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
index 994e2ba..09fd687 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/BackportedMethodRewriter.java
@@ -165,11 +165,9 @@
public void processSynthesizedClasses(IRConverter converter, ExecutorService executor)
throws ExecutionException {
while (!synthesizedMethods.isEmpty()) {
- List<ProgramMethod> methods = new ArrayList<>(synthesizedMethods);
+ ArrayList<ProgramMethod> methods = new ArrayList<>(synthesizedMethods);
synthesizedMethods.clear();
- for (ProgramMethod method : methods) {
- converter.optimizeSynthesizedClass(method.getHolder(), executor);
- }
+ converter.optimizeSynthesizedMethods(methods, executor);
}
}
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 11b4ddf..dbad5bd 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
@@ -10,26 +10,16 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.ClasspathMethod;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DebugLocalInfo;
-import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexProgramClass.ChecksumSupplier;
import com.android.tools.r8.graph.DexProto;
-import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
-import com.android.tools.r8.graph.GenericSignature.ClassSignature;
-import com.android.tools.r8.graph.GenericSignature.MethodTypeSignature;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
@@ -65,8 +55,8 @@
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
-import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.synthesis.SyntheticNaming.SyntheticKind;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
import com.android.tools.r8.utils.ListUtils;
@@ -76,7 +66,6 @@
import com.android.tools.r8.utils.collections.ProgramMethodMultiset;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import java.util.ArrayList;
-import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
@@ -102,9 +91,9 @@
* {@link OutlineOptions#threshold}). Each selected method is then converted back to IR and
* passed to {@link Outliner#identifyOutlineSites(IRCode)}, which then stores concrete
* outlining candidates in {@link Outliner#outlineSites}.
- * <li>Third, {@link Outliner#buildOutlinerClass(DexType)} is called to construct the <em>outline
- * support class</em> containing a static helper method for each outline candidate that occurs
- * frequently enough. Each selected method is then converted to IR, passed to {@link
+ * <li>Third, {@link Outliner#buildOutlineMethods()} is called to construct the <em>outline
+ * support classes</em> containing a static helper method for each outline candidate that
+ * occurs frequently enough. Each selected method is then converted to IR, passed to {@link
* Outliner#applyOutliningCandidate(IRCode)} to perform the outlining, and converted back to
* the output format (DEX or CF).
* </ul>
@@ -116,7 +105,7 @@
new ArrayList<>();
/** Result of second step (see {@link Outliner#selectMethodsForOutlining()}. */
private final Map<Outline, List<ProgramMethod>> outlineSites = new HashMap<>();
- /** Result of third step (see {@link Outliner#buildOutlinerClass(DexType)}. */
+ /** Result of third step (see {@link Outliner#buildOutlineMethods()}. */
private final Map<Outline, DexMethod> generatedOutlines = new HashMap<>();
static final int MAX_IN_SIZE = 5; // Avoid using ranged calls for outlined code.
@@ -581,11 +570,6 @@
return proto;
}
- // Build the DexMethod for this outline.
- DexMethod buildMethod(DexType clazz, DexString name) {
- return appView.dexItemFactory().createMethod(clazz, buildProto(), name);
- }
-
@Override
public boolean equals(Object other) {
if (!(other instanceof Outline)) {
@@ -1355,67 +1339,40 @@
return methodsSelectedForOutlining;
}
- public DexProgramClass buildOutlinerClass(DexType type) {
- // Build the outlined methods.
- // By now the candidates are the actual selected outlines. Name the generated methods in a
- // consistent order, to provide deterministic output.
+ public List<ProgramMethod> buildOutlineMethods() {
+ List<ProgramMethod> outlineMethods = new ArrayList<>();
+ // By now the candidates are the actual selected outlines. Iterate the outlines in a
+ // consistent order, to provide deterministic naming of the internal-synthetics.
+ // The choice of 'representative' will ensure deterministic naming of the external names.
List<Outline> outlines = selectOutlines();
outlines.sort(Comparator.naturalOrder());
- DexEncodedMethod[] direct = new DexEncodedMethod[outlines.size()];
- int count = 0;
for (Outline outline : outlines) {
- MethodAccessFlags methodAccess =
- MethodAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC | Constants.ACC_STATIC, false);
- DexString methodName =
- appView.dexItemFactory().createString(OutlineOptions.METHOD_PREFIX + count);
- DexMethod method = outline.buildMethod(type, methodName);
List<ProgramMethod> sites = outlineSites.get(outline);
assert !sites.isEmpty();
- direct[count] =
- new DexEncodedMethod(
- method,
- methodAccess,
- MethodTypeSignature.noSignature(),
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- new OutlineCode(outline),
- true);
- if (appView.options().isGeneratingClassFiles()) {
- direct[count].upgradeClassFileVersion(sites.get(0).getDefinition().getClassFileVersion());
- }
- generatedOutlines.put(outline, method);
- count++;
+ ProgramMethod representative = findDeterministicRepresentative(sites);
+ ProgramMethod outlineMethod =
+ appView
+ .getSyntheticItems()
+ .createMethod(
+ SyntheticKind.OUTLINE,
+ representative,
+ appView.dexItemFactory(),
+ builder -> {
+ builder
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_STATIC, false))
+ .setProto(outline.buildProto())
+ .setCode(m -> new OutlineCode(outline));
+ if (appView.options().isGeneratingClassFiles()) {
+ builder.setClassFileVersion(
+ representative.getDefinition().getClassFileVersion());
+ }
+ });
+ generatedOutlines.put(outline, outlineMethod.getReference());
+ outlineMethods.add(outlineMethod);
}
- // No need to sort the direct methods as they are generated in sorted order.
-
- // Build the outliner class.
- DexTypeList interfaces = DexTypeList.empty();
- DexString sourceFile = appView.dexItemFactory().createString("outline");
- ClassAccessFlags accessFlags = ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC);
- assert !appView.options().encodeChecksums;
- // The outliner is R8 only and checksum is not a supported part of R8 compilation.
- ChecksumSupplier checksumSupplier = DexProgramClass::invalidChecksumRequest;
- return new DexProgramClass(
- type,
- null,
- new SynthesizedOrigin("outlining", getClass()),
- accessFlags,
- appView.dexItemFactory().objectType,
- interfaces,
- sourceFile,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- ClassSignature.noSignature(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY, // Static fields.
- DexEncodedField.EMPTY_ARRAY, // Instance fields.
- direct,
- DexEncodedMethod.EMPTY_ARRAY, // Virtual methods.
- appView.dexItemFactory().getSkipNameValidationForTesting(),
- checksumSupplier);
+ return outlineMethods;
}
private List<Outline> selectOutlines() {
@@ -1430,6 +1387,18 @@
return result;
}
+ private static ProgramMethod findDeterministicRepresentative(List<ProgramMethod> members) {
+ // Pick a deterministic member as representative.
+ ProgramMethod smallest = members.get(0);
+ for (int i = 1; i < members.size(); i++) {
+ ProgramMethod next = members.get(i);
+ if (next.getReference().compareTo(smallest.getReference()) < 0) {
+ smallest = next;
+ }
+ }
+ return smallest;
+ }
+
public void applyOutliningCandidate(IRCode code) {
assert !code.method().getCode().isOutlineCode();
ListIterator<BasicBlock> blocksIterator = code.listIterator();
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 f7ac800..a9d8d57 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -109,7 +109,6 @@
import com.android.tools.r8.utils.Action;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
-import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
import com.android.tools.r8.utils.IteratorUtils;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
@@ -1724,8 +1723,6 @@
|| !options.testing.checkForNotExpandingMainDexTracingResult
|| previousMainDexTracingResult.isRoot(clazz)
|| clazz.toSourceString().contains(ENUM_UNBOXING_UTILITY_CLASS_SUFFIX)
- // TODO(b/177847090): Consider not outlining anything in main dex.
- || clazz.toSourceString().contains(OutlineOptions.CLASS_NAME)
: "Class " + clazz.toSourceString() + " was not a main dex root in the first round";
// Mark types in inner-class attributes referenced.
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
index b33e260..fc5b278 100644
--- a/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticNaming.java
@@ -32,7 +32,8 @@
THROW_ICCE("ThrowICCE", true),
THROW_NSME("ThrowNSME", true),
TWR_CLOSE_RESOURCE("TwrCloseResource", true),
- SERVICE_LOADER("ServiceLoad", true);
+ SERVICE_LOADER("ServiceLoad", true),
+ OUTLINE("Outline", true);
public final String descriptor;
public final boolean isSingleSyntheticMethod;
diff --git a/src/main/java/com/android/tools/r8/utils/InternalOptions.java b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
index a8bec4a..a9f55ee 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -1067,10 +1067,6 @@
}
public static class OutlineOptions {
-
- public static final String CLASS_NAME = "com.android.tools.r8.GeneratedOutlineSupport";
- public static final String METHOD_PREFIX = "outline";
-
public boolean enabled = true;
public int minSize = 3;
public int maxSize = 99;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/NoOutliningForClassFileBuildsTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/NoOutliningForClassFileBuildsTest.java
index 4af2593..2a837bc 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/NoOutliningForClassFileBuildsTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/NoOutliningForClassFileBuildsTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
-import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -72,8 +72,9 @@
assertThat(classSubject.uniqueMethodWithName("foo"), isPresent());
assertThat(classSubject.uniqueMethodWithName("bar"), isPresent());
boolean hasOutlineClass =
- inspector.allClasses().stream()
- .anyMatch(c -> c.getFinalName().equals(OutlineOptions.CLASS_NAME));
+ inspector
+ .clazz(SyntheticItemsTestUtils.syntheticOutlineClass(TestClass.class, 0))
+ .isPresent();
assertEquals(forceOutline || parameters.isDexRuntime(), hasOutlineClass);
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java
index 59602da..6b7bc4a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/OutlinesWithNonNullTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -93,9 +93,10 @@
}
private void validateOutlining(CodeInspector inspector, Class<?> main) {
- ClassSubject outlineClass = inspector.clazz(OutlineOptions.CLASS_NAME);
- assertThat(outlineClass, isPresent());
- MethodSubject outlineMethod = outlineClass.uniqueMethodWithName("outline0");
+ ClassSubject outlineClass =
+ inspector.clazz(SyntheticItemsTestUtils.syntheticOutlineClass(main, 0));
+ MethodSubject outlineMethod =
+ outlineClass.uniqueMethodWithName(SyntheticItemsTestUtils.syntheticMethodName());
assertThat(outlineMethod, isPresent());
ClassSubject argClass = inspector.clazz(TestArg.class);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithClassArrayTypeArguments.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithClassArrayTypeArguments.java
index 099afa8..440b036 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithClassArrayTypeArguments.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithClassArrayTypeArguments.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -37,11 +37,12 @@
}
private void validateOutlining(CodeInspector inspector) {
- ClassSubject outlineClass = inspector.clazz(OutlineOptions.CLASS_NAME);
+ ClassSubject outlineClass =
+ inspector.clazz(SyntheticItemsTestUtils.syntheticOutlineClass(TestClass.class, 0));
MethodSubject outline0Method =
outlineClass.method(
"void",
- "outline0",
+ SyntheticItemsTestUtils.syntheticMethodName(),
ImmutableList.of(
TestClass.class.getTypeName() + "[]", TestClass.class.getTypeName() + "[]"));
assertThat(outline0Method, isPresent());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithInterfaceArrayTypeArguments.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithInterfaceArrayTypeArguments.java
index fb4417f9..062516c 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithInterfaceArrayTypeArguments.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithInterfaceArrayTypeArguments.java
@@ -11,8 +11,8 @@
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -44,12 +44,15 @@
private void validateOutlining(CodeInspector inspector) {
// No outlining when arrays of interfaces are involved, see b/132420510 - unless the testing
// option is set.
- ClassSubject outlineClass = inspector.clazz(OutlineOptions.CLASS_NAME);
+ ClassSubject outlineClass =
+ inspector.clazz(SyntheticItemsTestUtils.syntheticOutlineClass(TestClass.class, 0));
if (allowOutlinerInterfaceArrayArguments && parameters.isCfRuntime()) {
assertThat(outlineClass, isPresent());
MethodSubject outline0Method =
outlineClass.method(
- "void", "outline0", ImmutableList.of("java.lang.Object[]", "java.lang.Object[]"));
+ "void",
+ SyntheticItemsTestUtils.syntheticMethodName(),
+ ImmutableList.of("java.lang.Object[]", "java.lang.Object[]"));
assertThat(outline0Method, isPresent());
ClassSubject classSubject = inspector.clazz(TestClass.class);
assertThat(
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithPrimitiveArrayTypeArguments.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithPrimitiveArrayTypeArguments.java
index 7a69926..36d9ad5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithPrimitiveArrayTypeArguments.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/arraytypes/OutlinesWithPrimitiveArrayTypeArguments.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -37,9 +37,13 @@
}
private void validateOutlining(CodeInspector inspector) {
- ClassSubject outlineClass = inspector.clazz(OutlineOptions.CLASS_NAME);
+ ClassSubject outlineClass =
+ inspector.clazz(SyntheticItemsTestUtils.syntheticOutlineClass(TestClass.class, 0));
MethodSubject outline0Method =
- outlineClass.method("void", "outline0", ImmutableList.of("int[]", "int[]"));
+ outlineClass.method(
+ "void",
+ SyntheticItemsTestUtils.syntheticMethodName(),
+ ImmutableList.of("int[]", "int[]"));
assertThat(outline0Method, isPresent());
ClassSubject classSubject = inspector.clazz(TestClass.class);
assertThat(
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 9fcc6b7..b4dd6b7 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
@@ -10,6 +10,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
@@ -98,11 +99,14 @@
.inspector();
for (FoundClassSubject clazz : inspector.allClasses()) {
- clazz.forAllMethods(method -> {
- if (method.hasCode() && !method.getFinalName().startsWith("outline")) {
- verifyAbsenceOfStringBuilderAppend(method.streamInstructions());
- }
- });
+ if (!SyntheticItemsTestUtils.isExternalOutlineClass(clazz.getFinalReference())) {
+ clazz.forAllMethods(
+ method -> {
+ if (method.hasCode()) {
+ verifyAbsenceOfStringBuilderAppend(method.streamInstructions());
+ }
+ });
+ }
}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java
index 66c42e8..031fd9d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b133215941/B133215941.java
@@ -15,7 +15,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ir.optimize.outliner.b133215941.B133215941.TestClass.ClassWithStaticMethod;
-import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -41,11 +41,12 @@
}
private void validateOutlining(CodeInspector inspector) {
- ClassSubject outlineClass = inspector.clazz(OutlineOptions.CLASS_NAME);
+ ClassSubject outlineClass =
+ inspector.clazz(SyntheticItemsTestUtils.syntheticOutlineClass(TestClass.class, 0));
MethodSubject outline0Method =
outlineClass.method(
"void",
- "outline0",
+ SyntheticItemsTestUtils.syntheticMethodName(),
ImmutableList.of(TestClass.class.getTypeName(), TestClass.class.getTypeName()));
assertThat(outline0Method, isPresent());
ClassSubject classSubject = inspector.clazz(TestClass.class);
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b149971007/B149971007.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b149971007/B149971007.java
index 438aa81..dd6dace 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/b149971007/B149971007.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/b149971007/B149971007.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.ir.optimize.outliner.b149971007;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isAbsent;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
@@ -15,7 +16,7 @@
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.dexsplitter.SplitterTestBase;
import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundMethodSubject;
@@ -24,6 +25,8 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@@ -64,10 +67,17 @@
}
private void checkOutlineFromFeature(CodeInspector inspector) {
- ClassSubject clazz = inspector.clazz(OutlineOptions.CLASS_NAME);
- assertThat(clazz, isPresent());
- assertEquals(2, clazz.allMethods().size());
- assertTrue(clazz.allMethods().stream().anyMatch(this::referenceFeatureClass));
+ // There are two expected outlines, each is currently in its own class.
+ List<FoundMethodSubject> allMethods = new ArrayList<>();
+ for (int i = 0; i < 2; i++) {
+ ClassSubject clazz =
+ inspector.clazz(SyntheticItemsTestUtils.syntheticOutlineClass(FeatureClass.class, i));
+ assertThat(clazz, isPresent());
+ assertEquals(1, clazz.allMethods().size());
+ allMethods.addAll(clazz.allMethods());
+ }
+ // One of the methods is StringBuilder the other references the feature.
+ assertTrue(allMethods.stream().anyMatch(this::referenceFeatureClass));
}
@Test
@@ -85,24 +95,44 @@
// Check that parts of method1, ..., method4 in FeatureClass was outlined.
ClassSubject featureClass = compileResult.inspector().clazz(FeatureClass.class);
assertThat(featureClass, isPresent());
- String outlineClassName =
+
+ // Find the final names of the two outline classes.
+ String outlineClassName0 =
ClassNameMapper.mapperFromString(compileResult.getProguardMap())
.getObfuscatedToOriginalMapping()
.inverse
- .get(OutlineOptions.CLASS_NAME);
- assertTrue(invokesOutline(featureClass.uniqueMethodWithName("method1"), outlineClassName));
- assertTrue(invokesOutline(featureClass.uniqueMethodWithName("method2"), outlineClassName));
- assertTrue(invokesOutline(featureClass.uniqueMethodWithName("method3"), outlineClassName));
- assertTrue(invokesOutline(featureClass.uniqueMethodWithName("method4"), outlineClassName));
+ .get(
+ SyntheticItemsTestUtils.syntheticOutlineClass(FeatureClass.class, 0).getTypeName());
+ String outlineClassName1 =
+ ClassNameMapper.mapperFromString(compileResult.getProguardMap())
+ .getObfuscatedToOriginalMapping()
+ .inverse
+ .get(
+ SyntheticItemsTestUtils.syntheticOutlineClass(FeatureClass.class, 1).getTypeName());
+
+ // Verify they are called from the feature methods.
+ // Note: should the choice of synthetic grouping change these expectations will too.
+ assertTrue(invokesOutline(featureClass.uniqueMethodWithName("method1"), outlineClassName0));
+ assertTrue(invokesOutline(featureClass.uniqueMethodWithName("method2"), outlineClassName0));
+ assertTrue(invokesOutline(featureClass.uniqueMethodWithName("method3"), outlineClassName1));
+ assertTrue(invokesOutline(featureClass.uniqueMethodWithName("method4"), outlineClassName1));
compileResult.run(parameters.getRuntime(), TestClass.class).assertSuccessWithOutput("123456");
}
private void checkNoOutlineFromFeature(CodeInspector inspector) {
- ClassSubject clazz = inspector.clazz(OutlineOptions.CLASS_NAME);
- assertThat(clazz, isPresent());
- assertEquals(1, clazz.allMethods().size());
- assertTrue(clazz.allMethods().stream().noneMatch(this::referenceFeatureClass));
+ // The features do not give rise to an outline.
+ ClassSubject featureOutlineClass =
+ inspector.clazz(
+ SyntheticItemsTestUtils.syntheticOutlineClass(FeatureClass.class, 0).getTypeName());
+ assertThat(featureOutlineClass, isAbsent());
+ // The main TestClass entry does.
+ ClassSubject mainOutlineClazz =
+ inspector.clazz(
+ SyntheticItemsTestUtils.syntheticOutlineClass(TestClass.class, 0).getTypeName());
+ assertThat(mainOutlineClazz, isPresent());
+ assertEquals(1, mainOutlineClazz.allMethods().size());
+ assertTrue(mainOutlineClazz.allMethods().stream().noneMatch(this::referenceFeatureClass));
}
@Test
@@ -124,12 +154,16 @@
// Check that parts of method1, ..., method4 in FeatureClass was not outlined.
CodeInspector featureInspector = new CodeInspector(featureCode);
ClassSubject featureClass = featureInspector.clazz(FeatureClass.class);
+
+ // Note, this code does not really check a valid property now as the name of the outline is not
+ // known.
assertThat(featureClass, isPresent());
String outlineClassName =
ClassNameMapper.mapperFromString(compileResult.getProguardMap())
.getObfuscatedToOriginalMapping()
.inverse
- .get(OutlineOptions.CLASS_NAME);
+ .get(SyntheticItemsTestUtils.syntheticOutlineClass(TestClass.class, 0).getTypeName());
+
assertFalse(invokesOutline(featureClass.uniqueMethodWithName("method1"), outlineClassName));
assertFalse(invokesOutline(featureClass.uniqueMethodWithName("method2"), outlineClassName));
assertFalse(invokesOutline(featureClass.uniqueMethodWithName("method3"), outlineClassName));
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/classtypes/B134462736.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/classtypes/B134462736.java
index eab6811..39c95f1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/classtypes/B134462736.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/classtypes/B134462736.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -37,11 +37,12 @@
}
private void validateOutlining(CodeInspector inspector) {
- ClassSubject outlineClass = inspector.clazz(OutlineOptions.CLASS_NAME);
+ ClassSubject outlineClass =
+ inspector.clazz(SyntheticItemsTestUtils.syntheticOutlineClass(TestClass.class, 0));
MethodSubject outline0Method =
outlineClass.method(
"void",
- "outline0",
+ SyntheticItemsTestUtils.syntheticMethodName(),
ImmutableList.of(
StringBuilder.class.getTypeName(),
String.class.getTypeName(),
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java b/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java
index db3ef77..4b81714 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/outliner/primitivetypes/PrimitiveTypesTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
-import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -38,10 +38,13 @@
}
private void validateOutlining(CodeInspector inspector, Class<?> testClass, String argumentType) {
- ClassSubject outlineClass = inspector.clazz(OutlineOptions.CLASS_NAME);
+ ClassSubject outlineClass =
+ inspector.clazz(SyntheticItemsTestUtils.syntheticOutlineClass(testClass, 0));
MethodSubject outline0Method =
outlineClass.method(
- "java.lang.String", "outline0", ImmutableList.of(argumentType, argumentType));
+ "java.lang.String",
+ SyntheticItemsTestUtils.syntheticMethodName(),
+ ImmutableList.of(argumentType, argumentType));
assertThat(outline0Method, isPresent());
ClassSubject classSubject = inspector.clazz(testClass);
assertThat(
diff --git a/src/test/java/com/android/tools/r8/smali/OutlineTest.java b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
index 04ac085..efe3826 100644
--- a/src/test/java/com/android/tools/r8/smali/OutlineTest.java
+++ b/src/test/java/com/android/tools/r8/smali/OutlineTest.java
@@ -30,14 +30,18 @@
import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.references.ClassReference;
+import com.android.tools.r8.references.Reference;
import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
+import com.android.tools.r8.synthesis.SyntheticItemsTestUtils;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
import com.android.tools.r8.utils.StringUtils;
-import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Arrays;
@@ -50,6 +54,10 @@
public class OutlineTest extends SmaliTestBase {
+ private static ClassReference OUTLINE_CLASS =
+ SyntheticItemsTestUtils.syntheticOutlineClass(
+ Reference.classFromTypeName(DEFAULT_CLASS_NAME), 0);
+
private static final String stringBuilderAppendSignature =
"Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;";
private static final String stringBuilderAppendDoubleSignature =
@@ -85,12 +93,13 @@
}
private String firstOutlineMethodName() {
- return OutlineOptions.CLASS_NAME + '.' + OutlineOptions.METHOD_PREFIX + "0";
+ return OUTLINE_CLASS.getTypeName() + '.' + SyntheticItemsTestUtils.syntheticMethodName();
}
- private boolean isOutlineMethodName(String qualifiedName) {
- String qualifiedPrefix = OutlineOptions.CLASS_NAME + '.' + OutlineOptions.METHOD_PREFIX;
- return qualifiedName.indexOf(qualifiedPrefix) == 0;
+ private static boolean isOutlineMethodName(DexMethod method) {
+ return SyntheticItemsTestUtils.isExternalOutlineClass(
+ Reference.classFromDescriptor(method.holder.toDescriptorString()))
+ && method.name.toString().equals(SyntheticItemsTestUtils.syntheticMethodName());
}
@Test
@@ -142,7 +151,6 @@
AndroidApp originalApplication = buildApplication(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
// Return the processed method for inspection.
DexEncodedMethod method = getMethod(processedApplication, signature);
@@ -151,7 +159,7 @@
assertTrue(code.instructions[0] instanceof ConstString);
assertTrue(code.instructions[1] instanceof InvokeStatic);
InvokeStatic invoke = (InvokeStatic) code.instructions[1];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
// Run code and check result.
String result = runArt(processedApplication);
@@ -211,7 +219,6 @@
AndroidApp originalApplication = buildApplication(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
// Return the processed method for inspection.
DexEncodedMethod method = getMethod(processedApplication, signature);
@@ -225,7 +232,7 @@
}
assertTrue(code.instructions[firstOutlineInvoke] instanceof InvokeStatic);
InvokeStatic invoke = (InvokeStatic) code.instructions[firstOutlineInvoke];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
// Run code and check result.
String result = runArt(processedApplication);
@@ -273,7 +280,6 @@
Consumer<InternalOptions> options = configureOutlineOptions(outline -> outline.threshold = 1);
AndroidApp originalApplication = buildApplication(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
// Return the processed method for inspection.
DexEncodedMethod method = getMethod(processedApplication, signature);
@@ -282,7 +288,7 @@
assertTrue(code.instructions[0] instanceof ConstString);
assertTrue(code.instructions[1] instanceof InvokeStatic);
InvokeStatic invoke = (InvokeStatic) code.instructions[1];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
// Run code and check result.
String result = runArt(processedApplication);
@@ -336,7 +342,6 @@
Consumer<InternalOptions> options = configureOutlineOptions(outline -> outline.threshold = 1);
AndroidApp originalApplication = buildApplication(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
// Return the processed method for inspection.
DexEncodedMethod method = getMethod(processedApplication, signature);
@@ -346,7 +351,7 @@
assertTrue(code.instructions[1] instanceof ConstString);
assertTrue(code.instructions[2] instanceof InvokeStatic);
InvokeStatic invoke = (InvokeStatic) code.instructions[2];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
// Run code and check result.
String result = runArt(processedApplication);
@@ -402,7 +407,6 @@
AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
// Return the processed method for inspection.
DexEncodedMethod method = getMethod(processedApplication, signature);
@@ -412,13 +416,13 @@
if (i < 3) {
assertTrue(code.instructions[1] instanceof InvokeStatic);
InvokeStatic invoke = (InvokeStatic) code.instructions[1];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
} else {
assertTrue(code.instructions[1] instanceof InvokeVirtual);
assertTrue(code.instructions[2] instanceof InvokeVirtual);
assertTrue(code.instructions[3] instanceof InvokeStatic);
InvokeStatic invoke = (InvokeStatic) code.instructions[3];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
}
// Run code and check result.
@@ -480,7 +484,6 @@
AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
// Return the processed method for inspection.
DexEncodedMethod method = getMethod(processedApplication, signature);
@@ -490,13 +493,13 @@
if (i < 3) {
assertTrue(code.instructions[1] instanceof InvokeStatic);
InvokeStatic invoke = (InvokeStatic) code.instructions[1];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
} else {
assertTrue(code.instructions[1] instanceof InvokeVirtual);
assertTrue(code.instructions[2] instanceof InvokeVirtual);
assertTrue(code.instructions[3] instanceof InvokeStatic);
InvokeStatic invoke = (InvokeStatic) code.instructions[3];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
}
// Run code and check result.
@@ -553,7 +556,6 @@
AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
// Return the processed main method for inspection.
DexEncodedMethod mainMethod = getMethod(processedApplication, mainSignature);
@@ -569,14 +571,14 @@
}
if (i == 2) {
InvokeStatic invoke = (InvokeStatic) mainCode.instructions[4];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
} else if (i == 3) {
InvokeStatic invoke = (InvokeStatic) mainCode.instructions[1];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
} else {
assert i == 4 || i == 5;
InvokeStatic invoke = (InvokeStatic) mainCode.instructions[2];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
}
// Run code and check result.
@@ -653,19 +655,19 @@
AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
+ assertEquals(3, getNumberOfProgramClasses(processedApplication));
DexCode code1 = getMethod(processedApplication, signature1).getCode().asDexCode();
assertEquals(4, code1.instructions.length);
assertTrue(code1.instructions[1] instanceof InvokeStatic);
InvokeStatic invoke1 = (InvokeStatic) code1.instructions[1];
- assertTrue(isOutlineMethodName(invoke1.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke1.getMethod()));
DexCode code2 = getMethod(processedApplication, signature2).getCode().asDexCode();
assertEquals(5, code2.instructions.length);
assertTrue(code2.instructions[2] instanceof InvokeStatic);
InvokeStatic invoke2 = (InvokeStatic) code2.instructions[2];
- assertTrue(isOutlineMethodName(invoke1.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke1.getMethod()));
// Run code and check result.
String result = runArt(processedApplication);
@@ -721,7 +723,6 @@
AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
DexCode code = getMethod(processedApplication, signature).getCode().asDexCode();
int outlineInstructionIndex;
@@ -739,10 +740,10 @@
Instruction instruction = code.instructions[outlineInstructionIndex];
if (instruction instanceof InvokeStatic) {
InvokeStatic invoke = (InvokeStatic) instruction;
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
} else {
InvokeStaticRange invoke = (InvokeStaticRange) instruction;
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
}
// Run code and check result.
@@ -791,7 +792,7 @@
InvokeStatic invoke;
assertTrue(code.instructions[0] instanceof InvokeStatic);
invoke = (InvokeStatic) code.instructions[0];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
// Run code and check result.
String result = runArt(processedApplication);
@@ -859,16 +860,15 @@
AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
+ assertEquals(4, getNumberOfProgramClasses(processedApplication));
// Check that three outlining methods was created.
CodeInspector inspector = new CodeInspector(processedApplication);
- ClassSubject clazz = inspector.clazz(OutlineOptions.CLASS_NAME);
- assertTrue(clazz.isPresent());
- assertEquals(3, clazz.getDexProgramClass().getMethodCollection().numberOfDirectMethods());
+ List<DexEncodedMethod> outlineMethods = getOutlineMethods(inspector);
+ assertEquals(3, outlineMethods.size());
// Collect the return types of the outlines for the body of method1 and method2.
List<DexType> r = new ArrayList<>();
- for (DexEncodedMethod directMethod : clazz.getDexProgramClass().directMethods()) {
+ for (DexEncodedMethod directMethod : outlineMethods) {
if (directMethod.getCode().asDexCode().instructions[0] instanceof InvokeVirtual) {
r.add(directMethod.method.proto.returnType);
}
@@ -885,6 +885,16 @@
assertEquals("TestTestTestTestTest", result);
}
+ private static List<DexEncodedMethod> getOutlineMethods(CodeInspector inspector) {
+ List<DexEncodedMethod> outlineMethods = new ArrayList<>();
+ for (FoundClassSubject clazz : inspector.allClasses()) {
+ if (SyntheticItemsTestUtils.isExternalOutlineClass(clazz.getFinalReference())) {
+ clazz.forAllMethods(m -> outlineMethods.add(m.getMethod()));
+ }
+ }
+ return outlineMethods;
+ }
+
@Test
public void outlineMultipleTimes() throws Exception {
SmaliBuilder builder = new SmaliBuilder(DEFAULT_CLASS_NAME);
@@ -931,15 +941,18 @@
AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
+ assertEquals(3, getNumberOfProgramClasses(processedApplication));
final int count = 10;
- // Process the application several times. Each time will outline the previous outline.
- for (int i = 0; i < count; i++) {
+ // Process the application several times. Each time will outline the previous outlines.
+ for (int i = 1; i < count; i++) {
// Build a new application with the Outliner class.
originalApplication = processedApplication;
- processedApplication = processApplication(originalApplication, options);
- assertEquals(i + 3, getNumberOfProgramClasses(processedApplication));
+ processedApplication =
+ processApplication(
+ originalApplication,
+ options.andThen(o -> o.testing.allowConflictingSyntheticTypes = true));
+ assertEquals((i + 1) * 3, getNumberOfProgramClasses(processedApplication));
}
// Process the application several times. No more outlining as threshold has been raised.
@@ -954,7 +967,7 @@
// Build a new application with the Outliner class.
originalApplication = processedApplication;
processedApplication = processApplication(originalApplication, options);
- assertEquals(count - 1 + 3, getNumberOfProgramClasses(processedApplication));
+ assertEquals(count * 3, getNumberOfProgramClasses(processedApplication));
}
// Run the application with several levels of outlining.
@@ -1195,7 +1208,6 @@
AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
// Return the processed method for inspection.
DexEncodedMethod method1 = getMethod(processedApplication, signature1);
@@ -1205,7 +1217,7 @@
assertTrue(code1.instructions[1] instanceof MoveResult);
assertTrue(code1.instructions[2] instanceof Return);
InvokeStatic invoke1 = (InvokeStatic) code1.instructions[0];
- assertTrue(isOutlineMethodName(invoke1.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke1.getMethod()));
DexEncodedMethod method2 = getMethod(processedApplication, signature2);
DexCode code2 = method2.getCode().asDexCode();
@@ -1287,7 +1299,7 @@
assertTrue(code.instructions[5] instanceof Const4);
assertTrue(code.instructions[6] instanceof Return);
InvokeStatic invoke = (InvokeStatic) code.instructions[1];
- assertTrue(isOutlineMethodName(invoke.getMethod().qualifiedName()));
+ assertTrue(isOutlineMethodName(invoke.getMethod()));
// Run code and check result.
String result = runArt(processedApplication);
@@ -1614,15 +1626,13 @@
AndroidApp originalApplication = buildApplicationWithAndroidJar(builder);
AndroidApp processedApplication = processApplication(originalApplication, options);
- assertEquals(2, getNumberOfProgramClasses(processedApplication));
// Verify the code.
runDex2Oat(processedApplication);
}
private static boolean isOutlineInvoke(Instruction instruction) {
- return instruction instanceof InvokeStatic
- && instruction.getMethod().holder.toSourceString().equals(OutlineOptions.CLASS_NAME);
+ return instruction instanceof InvokeStatic && isOutlineMethodName(instruction.getMethod());
}
private void assertHasOutlineInvoke(DexEncodedMethod method) {
@@ -1699,10 +1709,10 @@
assertHasOutlineInvoke(getMethod(processedApplication, signature2));
assertThat(
new CodeInspector(processedApplication)
- .clazz(OutlineOptions.CLASS_NAME)
+ .clazz(OUTLINE_CLASS)
.method(
"boolean",
- "outline0",
+ SyntheticItemsTestUtils.syntheticMethodName(),
ImmutableList.of("java.io.PrintStream", "java.util.ArrayList")),
isPresent());
@@ -1774,8 +1784,11 @@
assertHasOutlineInvoke(getMethod(processedApplication, signature2));
assertThat(
new CodeInspector(processedApplication)
- .clazz(OutlineOptions.CLASS_NAME)
- .method("boolean", "outline0", ImmutableList.of("java.util.List")),
+ .clazz(OUTLINE_CLASS)
+ .method(
+ "boolean",
+ SyntheticItemsTestUtils.syntheticMethodName(),
+ ImmutableList.of("java.util.List")),
isPresent());
// Run code and check result.
@@ -1848,8 +1861,11 @@
assertHasOutlineInvoke(getMethod(processedApplication, signature2));
assertThat(
new CodeInspector(processedApplication)
- .clazz(OutlineOptions.CLASS_NAME)
- .method("boolean", "outline0", ImmutableList.of("java.util.ArrayList")),
+ .clazz(OUTLINE_CLASS)
+ .method(
+ "boolean",
+ SyntheticItemsTestUtils.syntheticMethodName(),
+ ImmutableList.of("java.util.ArrayList")),
isPresent());
// Run code and check result.
@@ -1922,8 +1938,11 @@
assertHasOutlineInvoke(getMethod(processedApplication, signature2));
assertThat(
new CodeInspector(processedApplication)
- .clazz(OutlineOptions.CLASS_NAME)
- .method("boolean", "outline0", ImmutableList.of("java.util.ArrayList")),
+ .clazz(OUTLINE_CLASS)
+ .method(
+ "boolean",
+ SyntheticItemsTestUtils.syntheticMethodName(),
+ ImmutableList.of("java.util.ArrayList")),
isPresent());
// Run code and check result.
diff --git a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
index 438d3f9..3f9c6af 100644
--- a/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
+++ b/src/test/java/com/android/tools/r8/synthesis/SyntheticItemsTestUtils.java
@@ -16,6 +16,10 @@
public class SyntheticItemsTestUtils {
+ public static String syntheticMethodName() {
+ return SyntheticNaming.INTERNAL_SYNTHETIC_METHOD_PREFIX;
+ }
+
public static ClassReference syntheticCompanionClass(Class<?> clazz) {
return Reference.classFromDescriptor(
InterfaceMethodRewriter.getCompanionClassDescriptor(
@@ -23,8 +27,11 @@
}
private static ClassReference syntheticClass(Class<?> clazz, SyntheticKind kind, int id) {
- return SyntheticNaming.makeSyntheticReferenceForTest(
- Reference.classFromClass(clazz), kind, "" + id);
+ return syntheticClass(Reference.classFromClass(clazz), kind, id);
+ }
+
+ private static ClassReference syntheticClass(ClassReference clazz, SyntheticKind kind, int id) {
+ return SyntheticNaming.makeSyntheticReferenceForTest(clazz, kind, "" + id);
}
public static MethodReference syntheticBackportMethod(Class<?> clazz, int id, Method method) {
@@ -33,10 +40,18 @@
MethodReference originalMethod = Reference.methodFromMethod(method);
return Reference.methodFromDescriptor(
syntheticHolder.getDescriptor(),
- SyntheticNaming.INTERNAL_SYNTHETIC_METHOD_PREFIX,
+ syntheticMethodName(),
originalMethod.getMethodDescriptor());
}
+ public static ClassReference syntheticOutlineClass(Class<?> clazz, int id) {
+ return syntheticClass(clazz, SyntheticKind.OUTLINE, id);
+ }
+
+ public static ClassReference syntheticOutlineClass(ClassReference clazz, int id) {
+ return syntheticClass(clazz, SyntheticKind.OUTLINE, id);
+ }
+
public static ClassReference syntheticLambdaClass(Class<?> clazz, int id) {
return syntheticClass(clazz, SyntheticNaming.SyntheticKind.LAMBDA, id);
}
@@ -67,6 +82,10 @@
return SyntheticNaming.isSynthetic(reference, Phase.EXTERNAL, SyntheticKind.TWR_CLOSE_RESOURCE);
}
+ public static boolean isExternalOutlineClass(ClassReference reference) {
+ return SyntheticNaming.isSynthetic(reference, Phase.EXTERNAL, SyntheticKind.OUTLINE);
+ }
+
public static Matcher<String> containsInternalSyntheticReference() {
return containsString(SyntheticNaming.getPhaseSeparator(Phase.INTERNAL));
}