Merge commit '8bfe2df23f8ed4d77f9832264e28479f08c193b2' into dev-release
diff --git a/build.gradle b/build.gradle
index 730d291..c47befd 100644
--- a/build.gradle
+++ b/build.gradle
@@ -35,7 +35,7 @@
ext {
androidSupportVersion = '25.4.0'
- asmVersion = '8.0' // When updating update tools/asmifier.py as well.
+ asmVersion = '8.0' // When updating update tools/asmifier.py and Toolhelper as well.
espressoVersion = '3.0.0'
fastutilVersion = '7.2.0'
guavaVersion = '23.0'
diff --git a/infra/config/global/cr-buildbucket.cfg b/infra/config/global/cr-buildbucket.cfg
index 87925c3..4fc504a 100644
--- a/infra/config/global/cr-buildbucket.cfg
+++ b/infra/config/global/cr-buildbucket.cfg
@@ -102,7 +102,7 @@
swarming_tags: "vpython:native-python-wrapper"
build_numbers: YES
recipe {
- properties: "mastername:internal.client.r8"
+ properties: "builder_group:internal.client.r8"
name: "rex"
}
mixins: "build_limited_scripts_slave recipe"
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 3651899..ab0d4dd 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -32,6 +32,7 @@
import com.android.tools.r8.naming.signature.GenericSignatureRewriter;
import com.android.tools.r8.origin.CommandLineOrigin;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.synthesis.SyntheticFinalization;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.CfgPrinter;
import com.android.tools.r8.utils.ExceptionUtils;
@@ -253,6 +254,12 @@
InspectorImpl.runInspections(options.outputInspections, appView.appInfo().classes());
if (options.isGeneratingClassFiles()) {
+ // TODO(b/158159959): Move this out so it is shared for both CF and DEX pipelines.
+ SyntheticFinalization.Result result =
+ appView.getSyntheticItems().computeFinalSynthetics(appView);
+ if (result != null) {
+ appView.setAppInfo(new AppInfo(result.commit, appView.appInfo().getMainDexClasses()));
+ }
new CfApplicationWriter(
appView,
marker,
@@ -283,15 +290,22 @@
appView, inputApp, options, executor, timing, appView.appInfo().app());
appView.setAppInfo(
new AppInfo(
- app,
- appView.appInfo().getMainDexClasses(),
- appView.appInfo().getSyntheticItems().commit(app)));
+ appView.appInfo().getSyntheticItems().commit(app),
+ appView.appInfo().getMainDexClasses()));
namingLens = NamingLens.getIdentityLens();
}
+
+ // TODO(b/158159959): Move this out so it is shared for both CF and DEX pipelines.
+ SyntheticFinalization.Result result =
+ appView.getSyntheticItems().computeFinalSynthetics(appView);
+ if (result != null) {
+ appView.setAppInfo(new AppInfo(result.commit, appView.appInfo().getMainDexClasses()));
+ }
+
new ApplicationWriter(
appView,
marker == null ? null : ImmutableList.copyOf(markers),
- GraphLens.getIdentityLens(),
+ appView.graphLens(),
InitClassLens.getDefault(),
namingLens,
null)
@@ -338,9 +352,8 @@
DexApplication cfApp = app.builder().replaceProgramClasses(nonDexProgramClasses).build();
appView.setAppInfo(
new AppInfo(
- cfApp,
- appView.appInfo().getMainDexClasses(),
- appView.appInfo().getSyntheticItems().commit(cfApp)));
+ appView.appInfo().getSyntheticItems().commit(cfApp),
+ appView.appInfo().getMainDexClasses()));
ConvertedCfFiles convertedCfFiles = new ConvertedCfFiles();
NamingLens prefixRewritingNamingLens =
PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView);
diff --git a/src/main/java/com/android/tools/r8/L8.java b/src/main/java/com/android/tools/r8/L8.java
index ef71e03..332b864 100644
--- a/src/main/java/com/android/tools/r8/L8.java
+++ b/src/main/java/com/android/tools/r8/L8.java
@@ -11,7 +11,6 @@
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.desugar.PrefixRewritingMapper;
@@ -22,6 +21,7 @@
import com.android.tools.r8.origin.CommandLineOrigin;
import com.android.tools.r8.shaking.AnnotationRemover;
import com.android.tools.r8.shaking.L8TreePruner;
+import com.android.tools.r8.synthesis.SyntheticFinalization;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -99,11 +99,7 @@
});
assert !options.cfToCfDesugar;
if (shrink) {
- AndroidApp r8CommandInputApp = r8Command.getInputApp();
- InternalOptions r8CommandInternalOptions = r8Command.getInternalOptions();
- // TODO(b/167843161): Disable temporarily enum unboxing in L8 due to naming issues.
- r8CommandInternalOptions.enableEnumUnboxing = false;
- R8.runForTesting(r8CommandInputApp, r8CommandInternalOptions);
+ R8.run(r8Command, executorService);
} else if (d8Command != null) {
D8.run(d8Command, executorService);
}
@@ -131,15 +127,17 @@
new IRConverter(appView, timing).convert(appView, executor);
+ SyntheticFinalization.Result result =
+ appView.getSyntheticItems().computeFinalSynthetics(appView);
+ if (result != null) {
+ appView.setAppInfo(new AppInfo(result.commit, appView.appInfo().getMainDexClasses()));
+ }
+
NamingLens namingLens = PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView);
new GenericSignatureRewriter(appView, namingLens).run(appView.appInfo().classes(), executor);
new CfApplicationWriter(
- appView,
- options.getMarker(Tool.L8),
- GraphLens.getIdentityLens(),
- namingLens,
- null)
+ appView, options.getMarker(Tool.L8), appView.graphLens(), namingLens, null)
.write(options.getClassFileConsumer());
options.printWarnings();
} catch (ExecutionException e) {
diff --git a/src/main/java/com/android/tools/r8/PrintUses.java b/src/main/java/com/android/tools/r8/PrintUses.java
index 7ffc5ae..a1d8b26 100644
--- a/src/main/java/com/android/tools/r8/PrintUses.java
+++ b/src/main/java/com/android/tools/r8/PrintUses.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import com.android.tools.r8.dex.ApplicationReader;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexApplication;
@@ -352,7 +353,9 @@
new ApplicationReader(inputApp, options, new Timing("PrintUses")).read().toDirect();
appInfo =
AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
- application, MainDexClasses.createEmptyMainDexClasses());
+ application,
+ ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
+ MainDexClasses.createEmptyMainDexClasses());
}
private void analyze() {
diff --git a/src/main/java/com/android/tools/r8/R8.java b/src/main/java/com/android/tools/r8/R8.java
index 7b94e97..9963a47 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -57,7 +57,6 @@
import com.android.tools.r8.ir.optimize.UnusedArgumentsCollector;
import com.android.tools.r8.ir.optimize.UnusedArgumentsCollector.UnusedArgumentsGraphLens;
import com.android.tools.r8.ir.optimize.enums.EnumUnboxingCfMethods;
-import com.android.tools.r8.ir.optimize.enums.EnumUnboxingRewriter;
import com.android.tools.r8.ir.optimize.enums.EnumValueInfoMapCollector;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
import com.android.tools.r8.jar.CfApplicationWriter;
@@ -103,6 +102,7 @@
import com.android.tools.r8.shaking.VerticalClassMerger;
import com.android.tools.r8.shaking.VerticalClassMergerGraphLens;
import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer;
+import com.android.tools.r8.synthesis.SyntheticFinalization;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.CfgPrinter;
@@ -314,13 +314,7 @@
InterfaceMethodRewriter.checkForAssumedLibraryTypes(appView.appInfo(), options);
BackportedMethodRewriter.registerAssumedLibraryTypes(options);
if (options.enableEnumUnboxing) {
- if (appView.definitionFor(options.itemFactory.enumUnboxingUtilityType) != null) {
- // The enum unboxing utility class can be created only during cf to dex compilation.
- // If this is true, we are recompiling the dex application with R8 (compilation-steps).
- options.enableEnumUnboxing = false;
- } else {
- EnumUnboxingCfMethods.registerSynthesizedCodeReferences(options.itemFactory);
- }
+ EnumUnboxingCfMethods.registerSynthesizedCodeReferences(options.itemFactory);
}
List<ProguardConfigurationRule> synthesizedProguardRules = new ArrayList<>();
@@ -412,12 +406,6 @@
TreePruner pruner = new TreePruner(appViewWithLiveness);
DirectMappedDexApplication prunedApp = pruner.run();
- if (options.enableEnumUnboxing) {
- DexProgramClass utilityClass =
- EnumUnboxingRewriter.synthesizeEmptyEnumUnboxingUtilityClass(appView);
- prunedApp = prunedApp.builder().addProgramClass(utilityClass).build();
- }
-
// Recompute the subtyping information.
Set<DexType> removedClasses = pruner.getRemovedClasses();
appView.setAppInfo(
@@ -614,8 +602,9 @@
CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
try {
IRConverter converter = new IRConverter(appView, timing, printer, mainDexTracingResult);
- DexApplication application = converter.optimize(executorService).asDirect();
- appView.setAppInfo(appView.appInfo().rebuild(previous -> application));
+ DexApplication application =
+ converter.optimize(appViewWithLiveness, executorService).asDirect();
+ appView.setAppInfo(appView.appInfo().rebuildWithClassHierarchy(previous -> application));
} finally {
timing.end();
}
@@ -818,6 +807,24 @@
}
}
+ // Add automatic main dex classes to an eventual manual list of classes.
+ if (!options.mainDexKeepRules.isEmpty()) {
+ appView.appInfo().getMainDexClasses().addAll(mainDexTracingResult);
+ }
+
+ SyntheticFinalization.Result result =
+ appView.getSyntheticItems().computeFinalSynthetics(appView);
+ if (result != null) {
+ if (appView.appInfo().hasLiveness()) {
+ appViewWithLiveness.setAppInfo(
+ appViewWithLiveness
+ .appInfo()
+ .rebuildWithLiveness(result.commit, result.removedSyntheticClasses));
+ } else {
+ appView.setAppInfo(appView.appInfo().rebuildWithClassHierarchy(result.commit));
+ }
+ }
+
// Perform minification.
NamingLens namingLens;
if (options.getProguardConfiguration().hasApplyMappingFile()) {
@@ -871,11 +878,6 @@
assert !options.isShrinking();
}
- // Add automatic main dex classes to an eventual manual list of classes.
- if (!options.mainDexKeepRules.isEmpty()) {
- appView.appInfo().getMainDexClasses().addAll(mainDexTracingResult);
- }
-
// Validity checks.
assert getDirectApp(appView).verifyCodeObjectsOwners();
assert appView.appInfo().classes().stream().allMatch(clazz -> clazz.isValid(options));
diff --git a/src/main/java/com/android/tools/r8/R8Command.java b/src/main/java/com/android/tools/r8/R8Command.java
index 6efe395..7c78db1 100644
--- a/src/main/java/com/android/tools/r8/R8Command.java
+++ b/src/main/java/com/android/tools/r8/R8Command.java
@@ -551,7 +551,7 @@
: getDesugaringState();
FeatureSplitConfiguration featureSplitConfiguration =
- !featureSplits.isEmpty() ? new FeatureSplitConfiguration(featureSplits, reporter) : null;
+ !featureSplits.isEmpty() ? new FeatureSplitConfiguration(featureSplits) : null;
R8Command command =
new R8Command(
diff --git a/src/main/java/com/android/tools/r8/ResourceShrinker.java b/src/main/java/com/android/tools/r8/ResourceShrinker.java
index 8174420..b01f9a3 100644
--- a/src/main/java/com/android/tools/r8/ResourceShrinker.java
+++ b/src/main/java/com/android/tools/r8/ResourceShrinker.java
@@ -168,7 +168,7 @@
processMethod(method);
}
- if (classDef.hasAnnotations()) {
+ if (classDef.hasClassOrMemberAnnotations()) {
processAnnotations(classDef);
}
}
diff --git a/src/main/java/com/android/tools/r8/bisect/Bisect.java b/src/main/java/com/android/tools/r8/bisect/Bisect.java
index 0dcca76..6a21762 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -14,6 +14,7 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.utils.AndroidApp;
@@ -191,7 +192,7 @@
new ApplicationWriter(
AppView.createForD8(AppInfo.createInitialAppInfo(app)),
null,
- null,
+ GraphLens.getIdentityLens(),
InitClassLens.getDefault(),
NamingLens.getIdentityLens(),
null);
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index 393297a..d9103a5 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -54,6 +54,7 @@
import com.android.tools.r8.naming.MemberNaming.Signature;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.position.MethodPosition;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.DexVersion;
import com.android.tools.r8.utils.InternalOptions;
@@ -319,6 +320,7 @@
for (DexType type : mapping.getTypes()) {
if (type.isClassType()) {
assert DexString.isValidSimpleName(apiLevel, type.getName());
+ assert SyntheticItems.verifyNotInternalSynthetic(type);
}
}
@@ -1270,7 +1272,7 @@
public int getOffsetForAnnotationsDirectory(DexProgramClass clazz) {
- if (!clazz.hasAnnotations()) {
+ if (!clazz.hasClassOrMemberAnnotations()) {
return Constants.NO_OFFSET;
}
int offset = annotationDirectories.getInt(clazzToAnnotationDirectory.get(clazz));
diff --git a/src/main/java/com/android/tools/r8/dex/VirtualFile.java b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
index 5e31d99..2e0ab82 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -8,6 +8,7 @@
import com.android.tools.r8.FeatureSplit;
import com.android.tools.r8.errors.DexFileOverflowDiagnostic;
import com.android.tools.r8.errors.InternalCompilerError;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexCallSite;
@@ -28,6 +29,7 @@
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.MainDexClasses;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -74,6 +76,7 @@
private static final int MAX_PREFILL_ENTRIES = MAX_ENTRIES - 5000;
private final int id;
+ private final GraphLens graphLens;
private final VirtualFileIndexedItemCollection indexedItems;
private final IndexedItemTransaction transaction;
private final FeatureSplit featureSplit;
@@ -118,6 +121,7 @@
DexProgramClass primaryClass,
FeatureSplit featureSplit) {
this.id = id;
+ this.graphLens = graphLens;
this.indexedItems = new VirtualFileIndexedItemCollection(graphLens, initClassLens, namingLens);
this.transaction =
new IndexedItemTransaction(indexedItems, appView, graphLens, initClassLens, namingLens);
@@ -438,14 +442,20 @@
}
protected Map<FeatureSplit, Set<DexProgramClass>> removeFeatureSplitClassesGetMapping() {
- if (options.featureSplitConfiguration == null) {
+ assert appView.appInfo().hasClassHierarchy() == appView.enableWholeProgramOptimizations();
+ if (!appView.appInfo().hasClassHierarchy()) {
+ return ImmutableMap.of();
+ }
+
+ ClassToFeatureSplitMap classToFeatureSplitMap =
+ appView.appInfo().withClassHierarchy().getClassToFeatureSplitMap();
+ if (classToFeatureSplitMap.isEmpty()) {
return ImmutableMap.of();
}
// Pull out the classes that should go into feature splits.
Map<FeatureSplit, Set<DexProgramClass>> featureSplitClasses =
- options.featureSplitConfiguration.getFeatureSplitClasses(
- classes, appView.appInfo().app().getProguardMap());
+ classToFeatureSplitMap.getFeatureSplitClasses(classes);
if (featureSplitClasses.size() > 0) {
for (Set<DexProgramClass> featureClasses : featureSplitClasses.values()) {
classes.removeAll(featureClasses);
@@ -627,12 +637,12 @@
@Override
public boolean addField(DexField field) {
- return fields.add(field);
+ return fields.add(graphLens.lookupField(field));
}
@Override
public boolean addMethod(DexMethod method) {
- return methods.add(method);
+ return methods.add(graphLens.lookupMethod(method));
}
@Override
@@ -647,7 +657,9 @@
@Override
public boolean addType(DexType type) {
- return types.add(type);
+ DexType rewritten = graphLens.lookupType(type);
+ assert SyntheticItems.verifyNotInternalSynthetic(rewritten);
+ return types.add(rewritten);
}
@Override
@@ -684,18 +696,19 @@
@Override
public DexString getRenamedDescriptor(DexType type) {
- return namingLens.lookupDescriptor(type);
+ return namingLens.lookupDescriptor(graphLens.lookupType(type));
}
@Override
public DexString getRenamedName(DexMethod method) {
- assert namingLens.verifyRenamingConsistentWithResolution(method);
- return namingLens.lookupName(method);
+ DexMethod mappedMethod = graphLens.lookupMethod(method);
+ assert namingLens.verifyRenamingConsistentWithResolution(mappedMethod);
+ return namingLens.lookupName(mappedMethod);
}
@Override
public DexString getRenamedName(DexField field) {
- return namingLens.lookupName(field);
+ return namingLens.lookupName(graphLens.lookupField(field));
}
}
@@ -748,12 +761,12 @@
@Override
public boolean addField(DexField field) {
- return maybeInsert(field, fields, base.fields);
+ return maybeInsert(base.graphLens.lookupField(field), fields, base.fields);
}
@Override
public boolean addMethod(DexMethod method) {
- return maybeInsert(method, methods, base.methods);
+ return maybeInsert(base.graphLens.lookupMethod(method), methods, base.methods);
}
@Override
@@ -768,7 +781,9 @@
@Override
public boolean addType(DexType type) {
- return maybeInsert(type, types, base.types);
+ DexType rewritten = base.graphLens.lookupType(type);
+ assert SyntheticItems.verifyNotInternalSynthetic(rewritten);
+ return maybeInsert(rewritten, types, base.types);
}
@Override
@@ -793,18 +808,19 @@
@Override
public DexString getRenamedDescriptor(DexType type) {
- return namingLens.lookupDescriptor(type);
+ return namingLens.lookupDescriptor(base.graphLens.lookupType(type));
}
@Override
public DexString getRenamedName(DexMethod method) {
- assert namingLens.verifyRenamingConsistentWithResolution(method);
- return namingLens.lookupName(method);
+ DexMethod mappedMethod = base.graphLens.lookupMethod(method);
+ assert namingLens.verifyRenamingConsistentWithResolution(mappedMethod);
+ return namingLens.lookupName(mappedMethod);
}
@Override
public DexString getRenamedName(DexField field) {
- return namingLens.lookupName(field);
+ return namingLens.lookupName(base.graphLens.lookupField(field));
}
int getNumberOfMethods() {
diff --git a/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
new file mode 100644
index 0000000..6ba885d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/features/ClassToFeatureSplitMap.java
@@ -0,0 +1,140 @@
+// Copyright (c) 2020, 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.features;
+
+import com.android.tools.r8.FeatureSplit;
+import com.android.tools.r8.ProgramResource;
+import com.android.tools.r8.ProgramResourceProvider;
+import com.android.tools.r8.ResourceException;
+import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.Sets;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class ClassToFeatureSplitMap {
+
+ private final Map<DexType, FeatureSplit> classToFeatureSplitMap = new IdentityHashMap<>();
+
+ private ClassToFeatureSplitMap() {}
+
+ public static ClassToFeatureSplitMap createEmptyClassToFeatureSplitMap() {
+ return new ClassToFeatureSplitMap();
+ }
+
+ public static ClassToFeatureSplitMap createInitialClassToFeatureSplitMap(
+ AppView<? extends AppInfoWithClassHierarchy> appView) {
+ return createInitialClassToFeatureSplitMap(appView.options());
+ }
+
+ public static ClassToFeatureSplitMap createInitialClassToFeatureSplitMap(
+ InternalOptions options) {
+ DexItemFactory dexItemFactory = options.dexItemFactory();
+ FeatureSplitConfiguration featureSplitConfiguration = options.featureSplitConfiguration;
+
+ ClassToFeatureSplitMap result = new ClassToFeatureSplitMap();
+ if (featureSplitConfiguration == null) {
+ return result;
+ }
+
+ for (FeatureSplit featureSplit : featureSplitConfiguration.getFeatureSplits()) {
+ for (ProgramResourceProvider programResourceProvider :
+ featureSplit.getProgramResourceProviders()) {
+ try {
+ for (ProgramResource programResource : programResourceProvider.getProgramResources()) {
+ for (String classDescriptor : programResource.getClassDescriptors()) {
+ DexType type = dexItemFactory.createType(classDescriptor);
+ result.classToFeatureSplitMap.put(type, featureSplit);
+ }
+ }
+ } catch (ResourceException e) {
+ throw options.reporter.fatalError(e.getMessage());
+ }
+ }
+ }
+ return result;
+ }
+
+ public Map<FeatureSplit, Set<DexProgramClass>> getFeatureSplitClasses(
+ Set<DexProgramClass> classes) {
+ Map<FeatureSplit, Set<DexProgramClass>> result = new IdentityHashMap<>();
+ for (DexProgramClass clazz : classes) {
+ FeatureSplit featureSplit = getFeatureSplit(clazz);
+ if (featureSplit != null && !featureSplit.isBase()) {
+ result.computeIfAbsent(featureSplit, ignore -> Sets.newIdentityHashSet()).add(clazz);
+ }
+ }
+ return result;
+ }
+
+ public FeatureSplit getFeatureSplit(DexProgramClass clazz) {
+ return getFeatureSplit(clazz.getType());
+ }
+
+ public FeatureSplit getFeatureSplit(DexType type) {
+ return classToFeatureSplitMap.getOrDefault(type, FeatureSplit.BASE);
+ }
+
+ public boolean isEmpty() {
+ return classToFeatureSplitMap.isEmpty();
+ }
+
+ public boolean isInBase(DexProgramClass clazz) {
+ return getFeatureSplit(clazz).isBase();
+ }
+
+ public boolean isInBaseOrSameFeatureAs(DexProgramClass clazz, DexProgramClass context) {
+ FeatureSplit split = getFeatureSplit(clazz);
+ return split.isBase() || split == getFeatureSplit(context);
+ }
+
+ public boolean isInFeature(DexProgramClass clazz) {
+ return !isInBase(clazz);
+ }
+
+ public boolean isInSameFeatureOrBothInBase(ProgramMethod a, ProgramMethod b) {
+ return isInSameFeatureOrBothInBase(a.getHolder(), b.getHolder());
+ }
+
+ public boolean isInSameFeatureOrBothInBase(DexProgramClass a, DexProgramClass b) {
+ return getFeatureSplit(a) == getFeatureSplit(b);
+ }
+
+ public ClassToFeatureSplitMap rewrittenWithLens(GraphLens lens) {
+ ClassToFeatureSplitMap rewrittenClassToFeatureSplitMap = new ClassToFeatureSplitMap();
+ classToFeatureSplitMap.forEach(
+ (type, featureSplit) -> {
+ DexType rewrittenType = lens.lookupType(type);
+ if (rewrittenType.isIntType()) {
+ // The type was removed by enum unboxing.
+ return;
+ }
+ FeatureSplit existing =
+ rewrittenClassToFeatureSplitMap.classToFeatureSplitMap.put(
+ rewrittenType, featureSplit);
+ // If we map two classes to the same class then they must be from the same feature split.
+ assert existing == null || existing == featureSplit;
+ });
+ return rewrittenClassToFeatureSplitMap;
+ }
+
+ public ClassToFeatureSplitMap withoutPrunedClasses(Set<DexType> prunedClasses) {
+ ClassToFeatureSplitMap classToFeatureSplitMapAfterPruning = new ClassToFeatureSplitMap();
+ classToFeatureSplitMap.forEach(
+ (type, featureSplit) -> {
+ if (!prunedClasses.contains(type)) {
+ classToFeatureSplitMapAfterPruning.classToFeatureSplitMap.put(type, featureSplit);
+ }
+ });
+ return classToFeatureSplitMapAfterPruning;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/features/FeatureSplitConfiguration.java b/src/main/java/com/android/tools/r8/features/FeatureSplitConfiguration.java
index 6e5b2ab..c357177 100644
--- a/src/main/java/com/android/tools/r8/features/FeatureSplitConfiguration.java
+++ b/src/main/java/com/android/tools/r8/features/FeatureSplitConfiguration.java
@@ -6,63 +6,19 @@
import com.android.tools.r8.DataResourceConsumer;
import com.android.tools.r8.DataResourceProvider;
import com.android.tools.r8.FeatureSplit;
-import com.android.tools.r8.ProgramResource;
import com.android.tools.r8.ProgramResourceProvider;
-import com.android.tools.r8.ResourceException;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.ProgramMethod;
-import com.android.tools.r8.naming.ClassNameMapper;
-import com.android.tools.r8.utils.DescriptorUtils;
-import com.android.tools.r8.utils.Reporter;
-import com.google.common.collect.Sets;
import java.util.ArrayList;
import java.util.Collection;
-import java.util.HashMap;
import java.util.HashSet;
-import java.util.IdentityHashMap;
import java.util.List;
-import java.util.Map;
import java.util.Set;
public class FeatureSplitConfiguration {
private final List<FeatureSplit> featureSplits;
- // TODO(141451259): Consider doing the mapping from DexType to Feature (with support in mapper).
- private final Map<String, FeatureSplit> javaTypeToFeatureSplitMapping = new HashMap<>();
-
- public FeatureSplitConfiguration(List<FeatureSplit> featureSplits, Reporter reporter) {
+ public FeatureSplitConfiguration(List<FeatureSplit> featureSplits) {
this.featureSplits = featureSplits;
- for (FeatureSplit featureSplit : featureSplits) {
- for (ProgramResourceProvider programResourceProvider :
- featureSplit.getProgramResourceProviders()) {
- try {
- for (ProgramResource programResource : programResourceProvider.getProgramResources()) {
- for (String classDescriptor : programResource.getClassDescriptors()) {
- javaTypeToFeatureSplitMapping.put(
- DescriptorUtils.descriptorToJavaType(classDescriptor), featureSplit);
- }
- }
- } catch (ResourceException e) {
- throw reporter.fatalError(e.getMessage());
- }
- }
- }
- }
-
- public Map<FeatureSplit, Set<DexProgramClass>> getFeatureSplitClasses(
- Set<DexProgramClass> classes, ClassNameMapper mapper) {
- Map<FeatureSplit, Set<DexProgramClass>> result = new IdentityHashMap<>();
-
- for (DexProgramClass programClass : classes) {
- String originalClassName =
- DescriptorUtils.descriptorToJavaType(programClass.type.toDescriptorString(), mapper);
- FeatureSplit featureSplit = javaTypeToFeatureSplitMapping.get(originalClassName);
- if (featureSplit != null) {
- result.computeIfAbsent(featureSplit, f -> Sets.newIdentityHashSet()).add(programClass);
- }
- }
- return result;
}
public static class DataResourceProvidersAndConsumer {
@@ -108,37 +64,7 @@
return result;
}
- public boolean inBaseOrSameFeatureAs(DexProgramClass clazz, DexProgramClass context) {
- FeatureSplit split = getFeatureSplit(clazz);
- return split.isBase() || split == getFeatureSplit(context);
- }
-
- public boolean isInFeature(DexProgramClass clazz) {
- return !isInBase(clazz);
- }
-
- public boolean isInBase(DexProgramClass clazz) {
- return getFeatureSplit(clazz).isBase();
- }
-
- public boolean inSameFeatureOrBothInBase(ProgramMethod a, ProgramMethod b) {
- return inSameFeatureOrBothInBase(a.getHolder(), b.getHolder());
- }
-
- public boolean inSameFeatureOrBothInBase(DexProgramClass a, DexProgramClass b) {
- return getFeatureSplit(a) == getFeatureSplit(b);
- }
-
public List<FeatureSplit> getFeatureSplits() {
return featureSplits;
}
-
- public FeatureSplit getFeatureSplitFromClassDescriptor(String classDescriptor) {
- return javaTypeToFeatureSplitMapping.get(DescriptorUtils.descriptorToJavaType(classDescriptor));
- }
-
- public FeatureSplit getFeatureSplit(DexProgramClass clazz) {
- return javaTypeToFeatureSplitMapping.getOrDefault(
- clazz.type.toSourceString(), FeatureSplit.BASE);
- }
}
diff --git a/src/main/java/com/android/tools/r8/graph/AccessControl.java b/src/main/java/com/android/tools/r8/graph/AccessControl.java
index 788b358..4bb68b9 100644
--- a/src/main/java/com/android/tools/r8/graph/AccessControl.java
+++ b/src/main/java/com/android/tools/r8/graph/AccessControl.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.features.FeatureSplitConfiguration;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.utils.OptionalBool;
/**
@@ -15,21 +15,18 @@
public class AccessControl {
public static OptionalBool isClassAccessible(
- DexClass clazz, ProgramMethod context, AppView<?> appView) {
+ DexClass clazz, ProgramMethod context, AppView<? extends AppInfoWithClassHierarchy> appView) {
return isClassAccessible(
- clazz, context.getHolder(), appView.options().featureSplitConfiguration);
+ clazz, context.getHolder(), appView.appInfo().getClassToFeatureSplitMap());
}
public static OptionalBool isClassAccessible(
- DexClass clazz,
- DexProgramClass context,
- FeatureSplitConfiguration featureSplitConfiguration) {
+ DexClass clazz, DexProgramClass context, ClassToFeatureSplitMap classToFeatureSplitMap) {
if (!clazz.isPublic() && !clazz.getType().isSamePackage(context.getType())) {
return OptionalBool.FALSE;
}
- if (featureSplitConfiguration != null
- && clazz.isProgramClass()
- && !featureSplitConfiguration.inBaseOrSameFeatureAs(clazz.asProgramClass(), context)) {
+ if (clazz.isProgramClass()
+ && !classToFeatureSplitMap.isInBaseOrSameFeatureAs(clazz.asProgramClass(), context)) {
return OptionalBool.UNKNOWN;
}
return OptionalBool.TRUE;
@@ -73,7 +70,7 @@
DexProgramClass context,
AppInfoWithClassHierarchy appInfo) {
OptionalBool classAccessibility =
- isClassAccessible(holder, context, appInfo.options().featureSplitConfiguration);
+ isClassAccessible(holder, context, appInfo.getClassToFeatureSplitMap());
if (classAccessibility.isFalse()) {
return OptionalBool.FALSE;
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfo.java b/src/main/java/com/android/tools/r8/graph/AppInfo.java
index c49eb28..6da4e08 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -3,12 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
-import com.android.tools.r8.graph.AppInfoWithClassHierarchy.CreateDesugaringViewOnAppInfo;
import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.MainDexClasses;
+import com.android.tools.r8.synthesis.CommittedItems;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.BooleanBox;
import com.android.tools.r8.utils.InternalOptions;
import java.util.Collection;
@@ -31,30 +32,28 @@
public static AppInfo createInitialAppInfo(
DexApplication application, MainDexClasses mainDexClasses) {
return new AppInfo(
- application,
- mainDexClasses,
- SyntheticItems.createInitialSyntheticItems(),
- new BooleanBox());
+ SyntheticItems.createInitialSyntheticItems().commit(application), mainDexClasses);
}
- public AppInfo(
- DexApplication application,
- MainDexClasses mainDexClasses,
- SyntheticItems.CommittedItems committedItems) {
- this(application, mainDexClasses, committedItems.toSyntheticItems(), new BooleanBox());
+ public AppInfo(CommittedItems committedItems, MainDexClasses mainDexClasses) {
+ this(
+ committedItems.getApplication(),
+ committedItems.toSyntheticItems(),
+ mainDexClasses,
+ new BooleanBox());
}
// For desugaring.
// This is a view onto the app info and is the only place the pending synthetics are shared.
- AppInfo(CreateDesugaringViewOnAppInfo witness, AppInfo appInfo) {
- this(appInfo.app, appInfo.mainDexClasses, appInfo.syntheticItems, appInfo.obsolete);
+ AppInfo(AppInfoWithClassHierarchy.CreateDesugaringViewOnAppInfo witness, AppInfo appInfo) {
+ this(appInfo.app, appInfo.syntheticItems, appInfo.mainDexClasses, appInfo.obsolete);
assert witness != null;
}
private AppInfo(
DexApplication application,
- MainDexClasses mainDexClasses,
SyntheticItems syntheticItems,
+ MainDexClasses mainDexClasses,
BooleanBox obsolete) {
this.app = application;
this.dexItemFactory = application.dexItemFactory;
@@ -105,7 +104,7 @@
public void addSynthesizedClass(DexProgramClass clazz, boolean addToMainDexClasses) {
assert checkIfObsolete();
- syntheticItems.addSyntheticClass(clazz);
+ syntheticItems.addLegacySyntheticClass(clazz);
if (addToMainDexClasses && !mainDexClasses.isEmpty()) {
mainDexClasses.add(clazz);
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
index 68ce78b..a1e3d15 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.utils.TraversalContinuation.BREAK;
import static com.android.tools.r8.utils.TraversalContinuation.CONTINUE;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.FieldResolutionResult.SuccessfulFieldResolutionResult;
import com.android.tools.r8.graph.ResolutionResult.ArrayCloneMethodResult;
import com.android.tools.r8.graph.ResolutionResult.ClassNotFoundResult;
@@ -16,6 +17,8 @@
import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
import com.android.tools.r8.shaking.MainDexClasses;
+import com.android.tools.r8.synthesis.CommittedItems;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.ListUtils;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.TraversalContinuation;
@@ -47,24 +50,30 @@
}
public static AppInfoWithClassHierarchy createInitialAppInfoWithClassHierarchy(
- DexApplication application, MainDexClasses mainDexClasses) {
+ DexApplication application,
+ ClassToFeatureSplitMap classToFeatureSplitMap,
+ MainDexClasses mainDexClasses) {
return new AppInfoWithClassHierarchy(
- application,
- mainDexClasses,
- SyntheticItems.createInitialSyntheticItems().commit(application));
+ SyntheticItems.createInitialSyntheticItems().commit(application),
+ classToFeatureSplitMap,
+ mainDexClasses);
}
- // For AppInfoWithLiveness.
+ private final ClassToFeatureSplitMap classToFeatureSplitMap;
+
+ // For AppInfoWithLiveness subclass.
protected AppInfoWithClassHierarchy(
- DexApplication application,
- MainDexClasses mainDexClasses,
- SyntheticItems.CommittedItems committedItems) {
- super(application, mainDexClasses, committedItems);
+ CommittedItems committedItems,
+ ClassToFeatureSplitMap classToFeatureSplitMap,
+ MainDexClasses mainDexClasses) {
+ super(committedItems, mainDexClasses);
+ this.classToFeatureSplitMap = classToFeatureSplitMap;
}
// For desugaring.
private AppInfoWithClassHierarchy(CreateDesugaringViewOnAppInfo witness, AppInfo appInfo) {
super(witness, appInfo);
+ this.classToFeatureSplitMap = ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap();
}
public static AppInfoWithClassHierarchy createForDesugaring(AppInfo appInfo) {
@@ -72,10 +81,20 @@
return new AppInfoWithClassHierarchy(WITNESS, appInfo);
}
- public AppInfoWithClassHierarchy rebuild(Function<DexApplication, DexApplication> fn) {
- DexApplication application = fn.apply(app());
+ public final AppInfoWithClassHierarchy rebuildWithClassHierarchy(CommittedItems commit) {
+ return new AppInfoWithClassHierarchy(commit, getClassToFeatureSplitMap(), getMainDexClasses());
+ }
+
+ public AppInfoWithClassHierarchy rebuildWithClassHierarchy(
+ Function<DexApplication, DexApplication> fn) {
return new AppInfoWithClassHierarchy(
- application, getMainDexClasses(), getSyntheticItems().commit(application));
+ getSyntheticItems().commit(fn.apply(app())),
+ getClassToFeatureSplitMap(),
+ getMainDexClasses());
+ }
+
+ public ClassToFeatureSplitMap getClassToFeatureSplitMap() {
+ return classToFeatureSplitMap;
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/AppServices.java b/src/main/java/com/android/tools/r8/graph/AppServices.java
index f853b30..de7599a 100644
--- a/src/main/java/com/android/tools/r8/graph/AppServices.java
+++ b/src/main/java/com/android/tools/r8/graph/AppServices.java
@@ -12,7 +12,9 @@
import com.android.tools.r8.ProgramResourceProvider;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.StringUtils;
@@ -71,8 +73,10 @@
return builder.build();
}
- public boolean hasServiceImplementationsInFeature(DexType serviceType) {
- if (appView.options().featureSplitConfiguration == null) {
+ public boolean hasServiceImplementationsInFeature(
+ AppView<AppInfoWithLiveness> appView, DexType serviceType) {
+ ClassToFeatureSplitMap classToFeatureSplitMap = appView.appInfo().getClassToFeatureSplitMap();
+ if (classToFeatureSplitMap.isEmpty()) {
return false;
}
Map<FeatureSplit, List<DexType>> featureImplementations = services.get(serviceType);
@@ -89,12 +93,12 @@
}
// Check if service is defined feature
DexProgramClass serviceClass = appView.definitionForProgramType(serviceType);
- if (appView.options().featureSplitConfiguration.isInFeature(serviceClass)) {
+ if (classToFeatureSplitMap.isInFeature(serviceClass)) {
return true;
}
for (DexType dexType : featureImplementations.get(FeatureSplit.BASE)) {
DexProgramClass implementationClass = appView.definitionForProgramType(dexType);
- if (appView.options().featureSplitConfiguration.isInFeature(implementationClass)) {
+ if (classToFeatureSplitMap.isInFeature(implementationClass)) {
return true;
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/AppView.java b/src/main/java/com/android/tools/r8/graph/AppView.java
index 2a181bc..f89f265 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.DexValue.DexValueString;
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.graph.analysis.InitializedClassesInInstanceMethodsAnalysis.InitializedClassesInInstanceMethods;
@@ -27,6 +28,7 @@
import com.android.tools.r8.shaking.LibraryModeledPredicate;
import com.android.tools.r8.shaking.MainDexClasses;
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.ThrowingConsumer;
@@ -135,9 +137,11 @@
public static AppView<AppInfoWithClassHierarchy> createForR8(
DexApplication application, MainDexClasses mainDexClasses) {
+ ClassToFeatureSplitMap classToFeatureSplitMap =
+ ClassToFeatureSplitMap.createInitialClassToFeatureSplitMap(application.options);
AppInfoWithClassHierarchy appInfo =
AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
- application, mainDexClasses);
+ application, classToFeatureSplitMap, mainDexClasses);
return new AppView<>(
appInfo, WholeProgramOptimizations.ON, defaultPrefixRewritingMapper(appInfo));
}
@@ -266,6 +270,10 @@
return wholeProgramOptimizations == WholeProgramOptimizations.ON;
}
+ public SyntheticItems getSyntheticItems() {
+ return appInfo.getSyntheticItems();
+ }
+
public CallSiteOptimizationInfoPropagator callSiteOptimizationInfoPropagator() {
return callSiteOptimizationInfoPropagator;
}
@@ -358,6 +366,10 @@
return initClassLens;
}
+ public boolean hasInitClassLens() {
+ return initClassLens != null;
+ }
+
public void setInitClassLens(InitClassLens initClassLens) {
this.initClassLens = initClassLens;
}
@@ -514,6 +526,11 @@
}
}
+ public void rewriteWithApplication(DirectMappedDexApplication application) {
+ assert application != null;
+ rewriteWithLens(null, application, withLiveness());
+ }
+
public void rewriteWithLensAndApplication(
NestedGraphLens lens, DirectMappedDexApplication application) {
assert lens != null;
@@ -525,9 +542,14 @@
NestedGraphLens lens,
DirectMappedDexApplication application,
AppView<AppInfoWithLiveness> appView) {
- boolean changed = appView.setGraphLens(lens);
- assert changed;
- assert application.verifyWithLens(lens);
+ if (lens != null) {
+ boolean changed = appView.setGraphLens(lens);
+ assert changed;
+ assert application.verifyWithLens(lens);
+ }
appView.setAppInfo(appView.appInfo().rewrittenWithLens(application, lens));
+ if (appView.hasInitClassLens()) {
+ appView.setInitClassLens(appView.initClassLens().rewrittenWithLens(lens));
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/DefaultInitClassLens.java b/src/main/java/com/android/tools/r8/graph/DefaultInitClassLens.java
index 56a1733..ec2f4c6 100644
--- a/src/main/java/com/android/tools/r8/graph/DefaultInitClassLens.java
+++ b/src/main/java/com/android/tools/r8/graph/DefaultInitClassLens.java
@@ -20,4 +20,9 @@
public DexField getInitClassField(DexType type) {
throw new Unreachable("Unexpected InitClass instruction for `" + type.toSourceString() + "`");
}
+
+ @Override
+ public InitClassLens rewrittenWithLens(GraphLens lens) {
+ return this;
+ }
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
index e1965be..237838f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
+++ b/src/main/java/com/android/tools/r8/graph/DexAnnotationElement.java
@@ -17,6 +17,10 @@
this.value = value;
}
+ public DexValue getValue() {
+ return value;
+ }
+
@Override
public int hashCode() {
return name.hashCode() + value.hashCode() * 3;
diff --git a/src/main/java/com/android/tools/r8/graph/DexApplication.java b/src/main/java/com/android/tools/r8/graph/DexApplication.java
index 67870ab..516edc0 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -10,6 +10,7 @@
import com.android.tools.r8.dex.ApplicationReader.ProgramClassConflictResolver;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.synthesis.SyntheticDefinitionsProvider;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ProgramClassCollection;
import com.android.tools.r8.utils.Timing;
diff --git a/src/main/java/com/android/tools/r8/graph/DexClass.java b/src/main/java/com/android/tools/r8/graph/DexClass.java
index 528b79b..e3bf2d8 100644
--- a/src/main/java/com/android/tools/r8/graph/DexClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexClass.java
@@ -723,6 +723,10 @@
return enclosingMethod;
}
+ public void setEnclosingMethodAttribute(EnclosingMethodAttribute enclosingMethod) {
+ this.enclosingMethod = enclosingMethod;
+ }
+
public void clearEnclosingMethodAttribute() {
enclosingMethod = null;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java b/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
index 9391a83..4125ca0 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
@@ -48,6 +48,10 @@
return DexProgramClass.asProgramClassOrNull(definitionFor(type, context));
}
+ default DexProgramClass programDefinitionFor(DexType type, ProgramMethod context) {
+ return programDefinitionFor(type, context.getHolder());
+ }
+
default <D extends DexEncodedMember<D, R>, R extends DexMember<D, R>>
DexClass definitionForHolder(DexEncodedMember<D, R> member, ProgramMethod context) {
return definitionForHolder(member.toReference(), context.getHolder());
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
index 0ed6769..e480799 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedAnnotation.java
@@ -30,6 +30,14 @@
}
}
+ public DexAnnotationElement getElement(int i) {
+ return elements[i];
+ }
+
+ public int getNumberOfElements() {
+ return elements.length;
+ }
+
@Override
void collectMixedSectionItems(MixedSectionCollection mixedItems) {
// Should never be called.
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
index 2ca1b48..c40383d 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -73,11 +73,13 @@
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.Pair;
import com.google.common.collect.ImmutableList;
+import com.google.common.hash.Hasher;
import it.unimi.dsi.fastutil.ints.Int2ReferenceArrayMap;
import it.unimi.dsi.fastutil.ints.Int2ReferenceMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
@@ -268,6 +270,41 @@
assert parameterAnnotationsList != null;
}
+ public void hashSyntheticContent(Hasher hasher) {
+ // Method holder does not contribute to the synthetic hash (it is freely chosen).
+ // Method name does not contribute to the synthetic hash (it is freely chosen).
+ method.proto.hashSyntheticContent(hasher);
+ hasher.putInt(accessFlags.getAsCfAccessFlags());
+ assert annotations().isEmpty();
+ assert parameterAnnotationsList.isEmpty();
+ assert code != null;
+ // TODO(b/158159959): Implement a more precise hashing on code objects.
+ if (code.isCfCode()) {
+ CfCode cfCode = code.asCfCode();
+ hasher.putInt(cfCode.instructions.size());
+ for (CfInstruction instruction : cfCode.instructions) {
+ hasher.putInt(instruction.getClass().hashCode());
+ }
+ } else {
+ assert code.isDexCode();
+ hasher.putInt(code.hashCode());
+ }
+ }
+
+ public boolean isSyntheticContentEqual(DexEncodedMethod other) {
+ return syntheticCompareTo(other) == 0;
+ }
+
+ public int syntheticCompareTo(DexEncodedMethod other) {
+ assert annotations().isEmpty();
+ assert parameterAnnotationsList.isEmpty();
+ return Comparator.comparing(DexEncodedMethod::proto, DexProto::slowCompareTo)
+ .thenComparingInt(m -> m.accessFlags.getAsCfAccessFlags())
+ // TODO(b/158159959): Implement structural compareTo on code.
+ .thenComparing(m -> m.getCode().toString())
+ .compare(this, other);
+ }
+
public DexType getHolderType() {
return getReference().holder;
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexField.java b/src/main/java/com/android/tools/r8/graph/DexField.java
index 19b793d..a58ec39 100644
--- a/src/main/java/com/android/tools/r8/graph/DexField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexField.java
@@ -13,12 +13,10 @@
public class DexField extends DexMember<DexEncodedField, DexField> {
public final DexType type;
- public final DexString name;
DexField(DexType holder, DexType type, DexString name, boolean skipNameValidationForTesting) {
- super(holder);
+ super(holder, name);
this.type = type;
- this.name = name;
if (!skipNameValidationForTesting && !name.isValidFieldName()) {
throw new CompilationError(
"Field name '" + name.toString() + "' cannot be represented in dex format.");
diff --git a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
index 91a70a9..4c3779e 100644
--- a/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
+++ b/src/main/java/com/android/tools/r8/graph/DexItemFactory.java
@@ -28,7 +28,6 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.code.Value;
import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaring;
-import com.android.tools.r8.ir.optimize.enums.EnumUnboxingRewriter;
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.utils.ArrayUtils;
import com.android.tools.r8.utils.LRUCacheTable;
@@ -443,12 +442,6 @@
createString("L" + NestBasedAccessDesugaring.NEST_CONSTRUCTOR_NAME + ";");
public final DexType nestConstructorType = createStaticallyKnownType(nestConstructorDescriptor);
- public final DexString enumUnboxingUtilityDescriptor =
- createString(
- "Lcom/android/tools/r8/" + EnumUnboxingRewriter.ENUM_UNBOXING_UTILITY_CLASS_NAME + ";");
- public final DexType enumUnboxingUtilityType =
- createStaticallyKnownType(enumUnboxingUtilityDescriptor);
-
public final StringBuildingMethods stringBuilderMethods =
new StringBuildingMethods(stringBuilderType);
public final StringBuildingMethods stringBufferMethods =
diff --git a/src/main/java/com/android/tools/r8/graph/DexMember.java b/src/main/java/com/android/tools/r8/graph/DexMember.java
index 02fd431..2a429d6 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMember.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMember.java
@@ -7,10 +7,13 @@
extends DexReference implements PresortedComparable<R> {
public final DexType holder;
+ public final DexString name;
- public DexMember(DexType holder) {
+ public DexMember(DexType holder, DexString name) {
assert holder != null;
this.holder = holder;
+ assert name != null;
+ this.name = name;
}
public DexEncodedMember<?, ?> lookupOnClass(DexClass clazz) {
diff --git a/src/main/java/com/android/tools/r8/graph/DexMethod.java b/src/main/java/com/android/tools/r8/graph/DexMethod.java
index 493bea3..26f114f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -18,12 +18,10 @@
public class DexMethod extends DexMember<DexEncodedMethod, DexMethod> {
public final DexProto proto;
- public final DexString name;
DexMethod(DexType holder, DexProto proto, DexString name, boolean skipNameValidationForTesting) {
- super(holder);
+ super(holder, name);
this.proto = proto;
- this.name = name;
if (!skipNameValidationForTesting && !name.isValidMethodName()) {
throw new CompilationError(
"Method name '" + name + "' in class '" + holder.toSourceString() +
diff --git a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
index a285398..f0efe20 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -269,7 +269,7 @@
void collectMixedSectionItems(MixedSectionCollection mixedItems) {
assert getEnclosingMethodAttribute() == null;
assert getInnerClasses().isEmpty();
- if (hasAnnotations()) {
+ if (hasClassOrMemberAnnotations()) {
mixedItems.setAnnotationsDirectoryForClass(this, new DexAnnotationDirectory(this));
}
}
@@ -363,7 +363,8 @@
return hasMethods() || hasFields();
}
- public boolean hasAnnotations() {
+ /** Determine if the class or any of its methods/fields has any attributes. */
+ public boolean hasClassOrMemberAnnotations() {
return !annotations().isEmpty()
|| hasAnnotations(methodCollection)
|| hasAnnotations(staticFields)
diff --git a/src/main/java/com/android/tools/r8/graph/DexProto.java b/src/main/java/com/android/tools/r8/graph/DexProto.java
index 77b9c42..09985c3 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProto.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProto.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.naming.NamingLens;
+import com.google.common.hash.Hasher;
public class DexProto extends IndexedDexItem implements PresortedComparable<DexProto> {
@@ -97,4 +98,11 @@
builder.append(lens.lookupDescriptor(returnType));
return builder.toString();
}
+
+ public void hashSyntheticContent(Hasher hasher) {
+ hasher.putInt(returnType.hashCode());
+ for (DexType param : parameters.values) {
+ hasher.putInt(param.hashCode());
+ }
+ }
}
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 fc14405..bc7e26f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -11,7 +11,7 @@
import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.EMULATE_LIBRARY_CLASS_NAME_SUFFIX;
import static com.android.tools.r8.ir.desugar.LambdaRewriter.LAMBDA_CLASS_NAME_PREFIX;
import static com.android.tools.r8.ir.desugar.LambdaRewriter.LAMBDA_GROUP_CLASS_NAME_PREFIX;
-import static com.android.tools.r8.ir.optimize.enums.EnumUnboxingRewriter.ENUM_UNBOXING_UTILITY_CLASS_NAME;
+import static com.android.tools.r8.ir.optimize.enums.UnboxedEnumMemberRelocator.ENUM_UNBOXING_UTILITY_CLASS_SUFFIX;
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.Unreachable;
@@ -22,6 +22,7 @@
import com.android.tools.r8.ir.optimize.ServiceLoaderRewriter;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions.OutlineOptions;
import com.google.common.base.Predicates;
@@ -291,6 +292,9 @@
return
// Hygienic suffix.
name.contains(COMPANION_CLASS_NAME_SUFFIX)
+ // New and hygienic synthesis infrastructure.
+ || name.contains(SyntheticItems.INTERNAL_SYNTHETIC_CLASS_SEPARATOR)
+ || name.contains(SyntheticItems.EXTERNAL_SYNTHETIC_CLASS_SEPARATOR)
// Only generated in core lib.
|| name.contains(EMULATE_LIBRARY_CLASS_NAME_SUFFIX)
|| name.contains(TYPE_WRAPPER_SUFFIX)
@@ -308,7 +312,7 @@
private static boolean isSynthesizedTypeThatCouldBeDuplicated(String name) {
// 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(ENUM_UNBOXING_UTILITY_CLASS_NAME) // Global singleton.
+ return name.contains(ENUM_UNBOXING_UTILITY_CLASS_SUFFIX) // Shared among enums.
|| name.contains(LAMBDA_CLASS_NAME_PREFIX) // Could collide.
|| name.contains(LAMBDA_GROUP_CLASS_NAME_PREFIX) // Could collide.
|| name.contains(DISPATCH_CLASS_NAME_SUFFIX) // Shared on reference.
diff --git a/src/main/java/com/android/tools/r8/graph/FinalInitClassLens.java b/src/main/java/com/android/tools/r8/graph/FinalInitClassLens.java
index 4f0a854..07e4dc2 100644
--- a/src/main/java/com/android/tools/r8/graph/FinalInitClassLens.java
+++ b/src/main/java/com/android/tools/r8/graph/FinalInitClassLens.java
@@ -28,4 +28,16 @@
public boolean isFinal() {
return true;
}
+
+ @Override
+ public InitClassLens rewrittenWithLens(GraphLens lens) {
+ InitClassLens.Builder builder = InitClassLens.builder();
+ mapping.forEach(
+ (type, field) -> {
+ DexType rewrittenType = lens.lookupType(type);
+ DexField rewrittenField = lens.lookupField(field);
+ builder.map(rewrittenType, rewrittenField);
+ });
+ return builder.build();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/graph/InitClassLens.java b/src/main/java/com/android/tools/r8/graph/InitClassLens.java
index cac3870..e3e7fd2 100644
--- a/src/main/java/com/android/tools/r8/graph/InitClassLens.java
+++ b/src/main/java/com/android/tools/r8/graph/InitClassLens.java
@@ -23,6 +23,8 @@
return false;
}
+ public abstract InitClassLens rewrittenWithLens(GraphLens lens);
+
public static class Builder {
private final Map<DexType, DexField> mapping = new ConcurrentHashMap<>();
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
index ecc7505..9839a80 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
@@ -55,6 +55,7 @@
Collection<DexCallSite> callSites,
Collection<DexMethodHandle> methodHandles) {
assert appInfo != null;
+ assert graphLens != null;
assert classes != null;
assert protos != null;
assert types != null;
@@ -251,11 +252,11 @@
}
public int getOffsetFor(DexField field) {
- return getOffsetFor(field, fields);
+ return getOffsetFor(graphLens.lookupField(field), fields);
}
public int getOffsetFor(DexMethod method) {
- return getOffsetFor(method, methods);
+ return getOffsetFor(graphLens.lookupMethod(method), methods);
}
public int getOffsetFor(DexString string) {
@@ -263,7 +264,7 @@
}
public int getOffsetFor(DexType type) {
- return getOffsetFor(type, types);
+ return getOffsetFor(graphLens.lookupType(type), types);
}
public int getOffsetFor(DexCallSite callSite) {
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramPackage.java b/src/main/java/com/android/tools/r8/graph/ProgramPackage.java
index c244576..c92c6d4 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramPackage.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramPackage.java
@@ -4,6 +4,7 @@
package com.android.tools.r8.graph;
+import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.Iterator;
import java.util.Set;
@@ -18,9 +19,9 @@
this.packageDescriptor = packageDescriptor;
}
- public void add(DexProgramClass clazz) {
+ public boolean add(DexProgramClass clazz) {
assert clazz.getType().getPackageDescriptor().equals(packageDescriptor);
- classes.add(clazz);
+ return classes.add(clazz);
}
public String getLastPackageName() {
@@ -43,6 +44,10 @@
forEach(clazz -> clazz.forEachProgramMethod(consumer));
}
+ public Set<DexProgramClass> classesInPackage() {
+ return ImmutableSet.copyOf(classes);
+ }
+
@Override
public Iterator<DexProgramClass> iterator() {
return classes.iterator();
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramPackageCollection.java b/src/main/java/com/android/tools/r8/graph/ProgramPackageCollection.java
index 57fc75a..fe9a64c 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramPackageCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramPackageCollection.java
@@ -16,15 +16,27 @@
this.packages = packages;
}
- public static ProgramPackageCollection create(AppView<?> appView) {
- Map<String, ProgramPackage> packages = new HashMap<>();
+ public static ProgramPackageCollection createWithAllProgramClasses(AppView<?> appView) {
assert !appView.appInfo().getSyntheticItems().hasPendingSyntheticClasses();
+ ProgramPackageCollection programPackages = new ProgramPackageCollection(new HashMap<>());
for (DexProgramClass clazz : appView.appInfo().classes()) {
- packages
- .computeIfAbsent(clazz.getType().getPackageDescriptor(), ProgramPackage::new)
- .add(clazz);
+ programPackages.addProgramClass(clazz);
}
- return new ProgramPackageCollection(packages);
+ return programPackages;
+ }
+
+ public static ProgramPackageCollection createEmpty() {
+ return new ProgramPackageCollection(new HashMap<>());
+ }
+
+ public boolean addProgramClass(DexProgramClass clazz) {
+ return packages
+ .computeIfAbsent(clazz.getType().getPackageDescriptor(), ProgramPackage::new)
+ .add(clazz);
+ }
+
+ public boolean isEmpty() {
+ return packages.isEmpty();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/SyntheticItems.java b/src/main/java/com/android/tools/r8/graph/SyntheticItems.java
deleted file mode 100644
index 3df048f..0000000
--- a/src/main/java/com/android/tools/r8/graph/SyntheticItems.java
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright (c) 2020, 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.graph;
-
-import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
-import com.google.common.collect.ImmutableSet;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.function.Function;
-
-public class SyntheticItems implements SyntheticDefinitionsProvider {
-
- public static class CommittedItems implements SyntheticDefinitionsProvider {
- // Set of all types that represent synthesized items.
- private final ImmutableSet<DexType> syntheticTypes;
-
- private CommittedItems(ImmutableSet<DexType> syntheticTypes) {
- this.syntheticTypes = syntheticTypes;
- }
-
- SyntheticItems toSyntheticItems() {
- return new SyntheticItems(syntheticTypes);
- }
-
- @Override
- public DexClass definitionFor(DexType type, Function<DexType, DexClass> baseDefinitionFor) {
- return baseDefinitionFor.apply(type);
- }
- }
-
- // Thread safe collection of synthesized classes that are not yet committed to the application.
- private final Map<DexType, DexProgramClass> pendingClasses = new ConcurrentHashMap<>();
-
- // Immutable set of types that represent synthetic definitions in the application (eg, committed).
- private final ImmutableSet<DexType> syntheticTypes;
-
- private SyntheticItems(ImmutableSet<DexType> syntheticTypes) {
- this.syntheticTypes = syntheticTypes;
- }
-
- public static SyntheticItems createInitialSyntheticItems() {
- return new SyntheticItems(ImmutableSet.of());
- }
-
- public boolean hasPendingSyntheticClasses() {
- return !pendingClasses.isEmpty();
- }
-
- public Collection<DexProgramClass> getPendingSyntheticClasses() {
- return Collections.unmodifiableCollection(pendingClasses.values());
- }
-
- @Override
- public DexClass definitionFor(DexType type, Function<DexType, DexClass> baseDefinitionFor) {
- DexProgramClass pending = pendingClasses.get(type);
- if (pending != null) {
- assert baseDefinitionFor.apply(type) == null
- : "Pending synthetic definition also present in the active program: " + type;
- return pending;
- }
- return baseDefinitionFor.apply(type);
- }
-
- // TODO(b/158159959): Remove the usage of this direct class addition (and name-based id).
- public void addSyntheticClass(DexProgramClass clazz) {
- assert clazz.type.isD8R8SynthesizedClassType();
- assert !syntheticTypes.contains(clazz.type);
- DexProgramClass previous = pendingClasses.put(clazz.type, clazz);
- assert previous == null || previous == clazz;
- }
-
- public boolean isSyntheticClass(DexType type) {
- return syntheticTypes.contains(type)
- || pendingClasses.containsKey(type)
- // TODO(b/158159959): Remove usage of name-based identification.
- || type.isD8R8SynthesizedClassType();
- }
-
- public boolean isSyntheticClass(DexProgramClass clazz) {
- return isSyntheticClass(clazz.type);
- }
-
- public CommittedItems commit(DexApplication application) {
- assert verifyAllPendingSyntheticsAreInApp(application, this);
- // All synthetics are in the app proper and no further meta-data is present so the empty
- // collection is currently returned here.
- ImmutableSet<DexType> merged = syntheticTypes;
- if (!pendingClasses.isEmpty()) {
- merged =
- ImmutableSet.<DexType>builder()
- .addAll(syntheticTypes)
- .addAll(pendingClasses.keySet())
- .build();
- }
- return new CommittedItems(merged);
- }
-
- public CommittedItems commit(DexApplication application, NestedGraphLens lens) {
- return new CommittedItems(lens.rewriteTypes(commit(application).syntheticTypes));
- }
-
- private static boolean verifyAllPendingSyntheticsAreInApp(
- DexApplication app, SyntheticItems synthetics) {
- for (DexProgramClass clazz : synthetics.getPendingSyntheticClasses()) {
- assert app.programDefinitionFor(clazz.type) != null;
- }
- return true;
- }
-}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
index a938abb..8b17c78 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -6,12 +6,16 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.horizontalclassmerging.policies.NoAnnotations;
import com.android.tools.r8.horizontalclassmerging.policies.NoFields;
+import com.android.tools.r8.horizontalclassmerging.policies.NoInnerClasses;
import com.android.tools.r8.horizontalclassmerging.policies.NoInterfaces;
-import com.android.tools.r8.horizontalclassmerging.policies.NoInternalUtilityClasses;
+import com.android.tools.r8.horizontalclassmerging.policies.NoKeepRules;
import com.android.tools.r8.horizontalclassmerging.policies.NoRuntimeTypeChecks;
import com.android.tools.r8.horizontalclassmerging.policies.NoStaticClassInitializer;
import com.android.tools.r8.horizontalclassmerging.policies.NotEntryPoint;
+import com.android.tools.r8.horizontalclassmerging.policies.NotMatchedByNoHorizontalClassMerging;
+import com.android.tools.r8.horizontalclassmerging.policies.RespectPackageBoundaries;
import com.android.tools.r8.horizontalclassmerging.policies.SameParentClass;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.ClassMergingEnqueuerExtension;
@@ -36,14 +40,18 @@
List<Policy> policies =
ImmutableList.of(
+ new NotMatchedByNoHorizontalClassMerging(appView),
new NoFields(),
// TODO(b/166071504): Allow merging of classes that implement interfaces.
new NoInterfaces(),
+ new NoAnnotations(),
+ new NoInnerClasses(),
new NoStaticClassInitializer(),
+ new NoKeepRules(appView),
new NoRuntimeTypeChecks(classMergingEnqueuerExtension),
new NotEntryPoint(appView.dexItemFactory()),
- new NoInternalUtilityClasses(appView.dexItemFactory()),
- new SameParentClass()
+ new SameParentClass(),
+ new RespectPackageBoundaries(appView)
// TODO: add policies
);
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
index 482ade5..b0e8d13 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
@@ -124,24 +124,40 @@
/** Bidirectional mapping from one method to another. */
public Builder moveMethod(DexMethod from, DexMethod to) {
+ if (from == to) {
+ return this;
+ }
+
mapMethod(from, to);
recordOriginalSignature(from, to);
return this;
}
public Builder recordOriginalSignature(DexMethod from, DexMethod to) {
+ if (from == to) {
+ return this;
+ }
+
originalMethodSignatures.forcePut(to, originalMethodSignatures.getOrDefault(from, from));
return this;
}
/** Unidirectional mapping from one method to another. */
public Builder recordExtraOriginalSignature(DexMethod from, DexMethod to) {
+ if (from == to) {
+ return this;
+ }
+
extraOriginalMethodSignatures.put(to, extraOriginalMethodSignatures.getOrDefault(from, from));
return this;
}
/** Unidirectional mapping from one method to another. */
public Builder mapMethod(DexMethod from, DexMethod to) {
+ if (from == to) {
+ return this;
+ }
+
for (DexMethod existingFrom :
completeInverseMethodMap.getOrDefault(from, Collections.emptySet())) {
methodMap.put(existingFrom, to);
@@ -151,8 +167,10 @@
.getOrDefault(existingFrom, Collections.emptySet())
.isEmpty();
}
+
methodMap.put(from, to);
completeInverseMethodMap.computeIfAbsent(to, ignore -> new HashSet<>()).add(from);
+
return this;
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/MultiClassPolicy.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/MultiClassPolicy.java
index 1ce2ee4..5c67423 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/MultiClassPolicy.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/MultiClassPolicy.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.horizontalclassmerging;
import com.android.tools.r8.graph.DexProgramClass;
+import java.util.ArrayList;
import java.util.Collection;
public abstract class MultiClassPolicy extends Policy {
@@ -13,6 +14,7 @@
* Remove all groups containing no or only a single class, as there is no point in merging these.
*/
protected void removeTrivialGroups(Collection<Collection<DexProgramClass>> groups) {
+ assert !(groups instanceof ArrayList);
groups.removeIf(group -> group.size() < 2);
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java
index 9ec4e5f..322958f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.graph.DexProgramClass;
import java.util.Collection;
import java.util.Iterator;
+import java.util.LinkedList;
import java.util.stream.Collectors;
/**
@@ -20,18 +21,12 @@
}
// TODO(b/165506334): if performing mutable operation ensure that linked lists are used
- private Collection<Collection<DexProgramClass>> applySingleClassPolicy(
- SingleClassPolicy policy, Collection<Collection<DexProgramClass>> groups) {
+ private LinkedList<Collection<DexProgramClass>> applySingleClassPolicy(
+ SingleClassPolicy policy, LinkedList<Collection<DexProgramClass>> groups) {
Iterator<Collection<DexProgramClass>> i = groups.iterator();
while (i.hasNext()) {
Collection<DexProgramClass> group = i.next();
- Iterator<DexProgramClass> j = group.iterator();
- while (j.hasNext()) {
- DexProgramClass clazz = j.next();
- if (!policy.canMerge(clazz)) {
- j.remove();
- }
- }
+ group.removeIf(clazz -> !policy.canMerge(clazz));
if (group.size() < 2) {
i.remove();
}
@@ -39,28 +34,36 @@
return groups;
}
- private Collection<Collection<DexProgramClass>> applyMultiClassPolicy(
- MultiClassPolicy policy, Collection<Collection<DexProgramClass>> groups) {
+ private LinkedList<Collection<DexProgramClass>> applyMultiClassPolicy(
+ MultiClassPolicy policy, LinkedList<Collection<DexProgramClass>> groups) {
// For each group apply the multi class policy and add all the new groups together.
return groups.stream()
.flatMap(group -> policy.apply(group).stream())
- .collect(Collectors.toList());
+ .collect(Collectors.toCollection(LinkedList::new));
}
@Override
public Collection<Collection<DexProgramClass>> run(
- Collection<Collection<DexProgramClass>> groups) {
+ Collection<Collection<DexProgramClass>> inputGroups) {
+ LinkedList<Collection<DexProgramClass>> linkedGroups;
+
+ if (inputGroups instanceof LinkedList) {
+ linkedGroups = (LinkedList<Collection<DexProgramClass>>) inputGroups;
+ } else {
+ linkedGroups = new LinkedList<>(inputGroups);
+ }
+
for (Policy policy : policies) {
if (policy instanceof SingleClassPolicy) {
- groups = applySingleClassPolicy((SingleClassPolicy) policy, groups);
+ linkedGroups = applySingleClassPolicy((SingleClassPolicy) policy, linkedGroups);
} else if (policy instanceof MultiClassPolicy) {
- groups = applyMultiClassPolicy((MultiClassPolicy) policy, groups);
+ linkedGroups = applyMultiClassPolicy((MultiClassPolicy) policy, linkedGroups);
}
// Any policy should not return any trivial groups.
- assert groups.stream().allMatch(group -> group.size() >= 2);
+ assert linkedGroups.stream().allMatch(group -> group.size() >= 2);
}
- return groups;
+ return linkedGroups;
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoAnnotations.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoAnnotations.java
new file mode 100644
index 0000000..f96a787
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoAnnotations.java
@@ -0,0 +1,15 @@
+// Copyright (c) 2020, 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.horizontalclassmerging.policies;
+
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
+
+public class NoAnnotations extends SingleClassPolicy {
+ @Override
+ public boolean canMerge(DexProgramClass program) {
+ return !program.hasClassOrMemberAnnotations();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInnerClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInnerClasses.java
new file mode 100644
index 0000000..ddb2aef
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInnerClasses.java
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, 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.horizontalclassmerging.policies;
+
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
+
+public class NoInnerClasses extends SingleClassPolicy {
+
+ @Override
+ public boolean canMerge(DexProgramClass program) {
+ return program.getInnerClasses().isEmpty();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInternalUtilityClasses.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInternalUtilityClasses.java
deleted file mode 100644
index 2887849..0000000
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoInternalUtilityClasses.java
+++ /dev/null
@@ -1,25 +0,0 @@
-// Copyright (c) 2020, 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.horizontalclassmerging.policies;
-
-import com.android.tools.r8.graph.DexItemFactory;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
-import java.util.Collections;
-import java.util.Set;
-
-public class NoInternalUtilityClasses extends SingleClassPolicy {
- private final Set<DexType> internalUtilityClasses;
-
- public NoInternalUtilityClasses(DexItemFactory dexItemFactory) {
- this.internalUtilityClasses = Collections.singleton(dexItemFactory.enumUnboxingUtilityType);
- }
-
- @Override
- public boolean canMerge(DexProgramClass program) {
- return !internalUtilityClasses.contains(program.type);
- }
-}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKeepRules.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKeepRules.java
new file mode 100644
index 0000000..6181c41
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NoKeepRules.java
@@ -0,0 +1,30 @@
+// Copyright (c) 2020, 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.horizontalclassmerging.policies;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.google.common.collect.Iterables;
+
+public class NoKeepRules extends SingleClassPolicy {
+ private final AppView<AppInfoWithLiveness> appView;
+
+ public NoKeepRules(AppView<AppInfoWithLiveness> appView) {
+ this.appView = appView;
+ }
+
+ @Override
+ public boolean canMerge(DexProgramClass program) {
+ DexType type = program.getType();
+ boolean anyPinned =
+ appView.appInfo().isPinned(type)
+ || Iterables.any(
+ program.members(), member -> appView.appInfo().isPinned(member.toReference()));
+ return !anyPinned;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NotMatchedByNoHorizontalClassMerging.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NotMatchedByNoHorizontalClassMerging.java
new file mode 100644
index 0000000..fbd17f3
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/NotMatchedByNoHorizontalClassMerging.java
@@ -0,0 +1,25 @@
+// Copyright (c) 2020, 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.horizontalclassmerging.policies;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.horizontalclassmerging.SingleClassPolicy;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import java.util.Set;
+
+public class NotMatchedByNoHorizontalClassMerging extends SingleClassPolicy {
+ private final Set<DexType> neverMergeClassHorizontally;
+
+ public NotMatchedByNoHorizontalClassMerging(AppView<AppInfoWithLiveness> appView) {
+ neverMergeClassHorizontally = appView.appInfo().getNoHorizontalClassMergingSet();
+ }
+
+ @Override
+ public boolean canMerge(DexProgramClass program) {
+ return !neverMergeClassHorizontally.contains(program.toReference());
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java
new file mode 100644
index 0000000..4b112b8
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/RespectPackageBoundaries.java
@@ -0,0 +1,102 @@
+// Copyright (c) 2020, 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.horizontalclassmerging.policies;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexEncodedMember;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.horizontalclassmerging.MultiClassPolicy;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.VerticalClassMerger.IllegalAccessDetector;
+import com.android.tools.r8.utils.TraversalContinuation;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.Map;
+
+public class RespectPackageBoundaries extends MultiClassPolicy {
+ private final AppView<AppInfoWithLiveness> appView;
+
+ public RespectPackageBoundaries(AppView<AppInfoWithLiveness> appView) {
+ this.appView = appView;
+ }
+
+ boolean shouldRestrictMergingAcrossPackageBoundary(DexProgramClass clazz) {
+ // Check that the class is public, otherwise it is package private.
+ if (!clazz.isPublic()) {
+ return true;
+ }
+
+ // If any members are package private or protected, then their access depends on the package.
+ for (DexEncodedMember<?, ?> member : clazz.members()) {
+ if (member.getAccessFlags().isPackagePrivateOrProtected()) {
+ return true;
+ }
+ }
+
+ // Check that all accesses from [clazz] to classes or members from the current package of
+ // [clazz] will continue to work. This is guaranteed if the methods of [clazz] do not access
+ // any private or protected classes or members from the current package of [clazz].
+ IllegalAccessDetector registry = new IllegalAccessDetector(appView, clazz);
+ TraversalContinuation result =
+ clazz.traverseProgramMethods(
+ method -> {
+ registry.setContext(method);
+ method.registerCodeReferences(registry);
+ if (registry.foundIllegalAccess()) {
+ return TraversalContinuation.BREAK;
+ }
+ return TraversalContinuation.CONTINUE;
+ });
+ return result.shouldBreak();
+ }
+
+ /** Sort unrestricted classes into restricted classes if they are in the same package. */
+ void tryFindRestrictedPackage(
+ LinkedList<DexProgramClass> unrestrictedClasses,
+ Map<String, Collection<DexProgramClass>> restrictedClasses) {
+ Iterator<DexProgramClass> i = unrestrictedClasses.iterator();
+ while (i.hasNext()) {
+ DexProgramClass clazz = i.next();
+ Collection<DexProgramClass> restrictedPackage =
+ restrictedClasses.get(clazz.type.getPackageDescriptor());
+ if (restrictedPackage != null) {
+ restrictedPackage.add(clazz);
+ i.remove();
+ }
+ }
+ }
+
+ @Override
+ public Collection<Collection<DexProgramClass>> apply(Collection<DexProgramClass> group) {
+ Map<String, Collection<DexProgramClass>> restrictedClasses = new LinkedHashMap<>();
+ LinkedList<DexProgramClass> unrestrictedClasses = new LinkedList<>();
+
+ // Sort all restricted classes into packages.
+ for (DexProgramClass clazz : group) {
+ if (shouldRestrictMergingAcrossPackageBoundary(clazz)) {
+ restrictedClasses
+ .computeIfAbsent(clazz.type.getPackageDescriptor(), ignore -> new ArrayList<>())
+ .add(clazz);
+ } else {
+ unrestrictedClasses.add(clazz);
+ }
+ }
+
+ tryFindRestrictedPackage(unrestrictedClasses, restrictedClasses);
+ removeTrivialGroups(restrictedClasses.values());
+
+ // TODO(b/166577694): Add the unrestricted classes to restricted groups, but ensure they aren't
+ // the merge target.
+ Collection<Collection<DexProgramClass>> groups = new ArrayList<>(restrictedClasses.size() + 1);
+ if (unrestrictedClasses.size() > 1) {
+ groups.add(unrestrictedClasses);
+ }
+ groups.addAll(restrictedClasses.values());
+ return groups;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
index 8d33495..1e93d1b 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/fieldaccess/TrivialFieldAccessReprocessor.java
@@ -107,7 +107,10 @@
private void enqueueMethodsForReprocessing(
AppInfoWithLiveness appInfo, ExecutorService executorService) throws ExecutionException {
ThreadUtils.processItems(appInfo.classes(), this::processClass, executorService);
- ThreadUtils.processItems(appInfo.synthesizedClasses(), this::processClass, executorService);
+ ThreadUtils.processItems(
+ appInfo.getSyntheticItems().getPendingSyntheticClasses(),
+ this::processClass,
+ executorService);
postMethodProcessorBuilder.put(methodsToReprocess);
}
@@ -145,7 +148,8 @@
private static boolean verifyNoConstantFieldsOnSynthesizedClasses(
AppView<AppInfoWithLiveness> appView) {
- for (DexProgramClass clazz : appView.appInfo().synthesizedClasses()) {
+ for (DexProgramClass clazz :
+ appView.appInfo().getSyntheticItems().getPendingSyntheticClasses()) {
for (DexEncodedField field : clazz.fields()) {
assert field.getOptimizationInfo().getAbstractValue().isUnknown();
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
index 96cdb99..c374875 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/proto/GeneratedMessageLiteBuilderShrinker.java
@@ -264,11 +264,19 @@
AppView<? extends AppInfoWithClassHierarchy> appView,
SubtypingInfo subtypingInfo,
PredicateSet<DexType> alwaysClassInline,
- Set<DexType> neverMerge,
+ Set<DexType> neverMergeClassVertically,
+ Set<DexType> neverMergeClassHorizontally,
+ Set<DexType> neverMergeStaticClassHorizontally,
Set<DexMethod> alwaysInline,
Set<DexMethod> bypassClinitforInlining) {
new RootSetExtension(
- appView, alwaysClassInline, neverMerge, alwaysInline, bypassClinitforInlining)
+ appView,
+ alwaysClassInline,
+ neverMergeClassVertically,
+ neverMergeClassHorizontally,
+ neverMergeStaticClassHorizontally,
+ alwaysInline,
+ bypassClinitforInlining)
.extend(subtypingInfo);
}
@@ -383,7 +391,9 @@
private final ProtoReferences references;
private final PredicateSet<DexType> alwaysClassInline;
- private final Set<DexType> neverMerge;
+ private final Set<DexType> neverMergeClassVertically;
+ private final Set<DexType> neverMergeClassHorizontally;
+ private final Set<DexType> neverMergeStaticClassHorizontally;
private final Set<DexMethod> alwaysInline;
private final Set<DexMethod> bypassClinitforInlining;
@@ -391,13 +401,17 @@
RootSetExtension(
AppView<? extends AppInfoWithClassHierarchy> appView,
PredicateSet<DexType> alwaysClassInline,
- Set<DexType> neverMerge,
+ Set<DexType> neverMergeClassVertically,
+ Set<DexType> neverMergeClassHorizontally,
+ Set<DexType> neverMergeStaticClassHorizontally,
Set<DexMethod> alwaysInline,
Set<DexMethod> bypassClinitforInlining) {
this.appView = appView;
this.references = appView.protoShrinker().references;
this.alwaysClassInline = alwaysClassInline;
- this.neverMerge = neverMerge;
+ this.neverMergeClassVertically = neverMergeClassVertically;
+ this.neverMergeClassHorizontally = neverMergeClassHorizontally;
+ this.neverMergeStaticClassHorizontally = neverMergeStaticClassHorizontally;
this.alwaysInline = alwaysInline;
this.bypassClinitforInlining = bypassClinitforInlining;
}
@@ -451,14 +465,20 @@
// For consistency, never merge the GeneratedMessageLite builders. These will only have a
// unique subtype if the application has a single proto message, which mostly happens during
// testing.
- neverMerge.add(references.generatedMessageLiteBuilderType);
- neverMerge.add(references.generatedMessageLiteExtendableBuilderType);
+ neverMergeClass(references.generatedMessageLiteBuilderType);
+ neverMergeClass(references.generatedMessageLiteExtendableBuilderType);
}
private void neverMergeMessageLite() {
// MessageLite is used in several signatures that we use for recognizing methods, so don't
// allow it to me merged.
- neverMerge.add(references.messageLiteType);
+ neverMergeClass(references.messageLiteType);
+ }
+
+ private void neverMergeClass(DexType type) {
+ neverMergeClassVertically.add(type);
+ neverMergeClassHorizontally.add(type);
+ neverMergeStaticClassHorizontally.add(type);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
index 7240424..8f4baa6 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleConstClassValue.java
@@ -87,9 +87,7 @@
DexClass clazz = appView.definitionFor(type);
return clazz != null
&& clazz.isResolvable(appView)
- && AccessControl.isClassAccessible(
- clazz, context.getHolder(), appView.options().featureSplitConfiguration)
- .isTrue();
+ && AccessControl.isClassAccessible(clazz, context, appView).isTrue();
}
assert baseType.isPrimitiveType();
return true;
diff --git a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
index 35767cc..7085e80 100644
--- a/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
+++ b/src/main/java/com/android/tools/r8/ir/code/CheckCast.java
@@ -108,6 +108,7 @@
if (type.isPrimitiveType()) {
return true;
}
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
DexType baseType = type.toBaseType(appView.dexItemFactory());
if (baseType.isClassType()) {
DexClass definition = appView.definitionFor(baseType);
@@ -116,11 +117,11 @@
return true;
}
// Check that the class is accessible.
- if (AccessControl.isClassAccessible(definition, context, appView).isPossiblyFalse()) {
+ if (AccessControl.isClassAccessible(definition, context, appViewWithLiveness)
+ .isPossiblyFalse()) {
return true;
}
}
- AppView<? extends AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
TypeElement castType = TypeElement.fromDexType(type, definitelyNotNull(), appView);
if (object()
.getDynamicUpperBoundType(appViewWithLiveness)
diff --git a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
index d28135d..86101ba 100644
--- a/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/ir/code/ConstClass.java
@@ -114,13 +114,16 @@
return true;
}
+ assert appView.appInfo().hasLiveness();
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+
DexClass clazz = appView.definitionFor(baseType);
// * Check that the class and its super types are present.
if (clazz == null || !clazz.isResolvable(appView)) {
return true;
}
// * Check that the class is accessible.
- if (AccessControl.isClassAccessible(clazz, context, appView).isPossiblyFalse()) {
+ if (AccessControl.isClassAccessible(clazz, context, appViewWithLiveness).isPossiblyFalse()) {
return true;
}
return false;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InitClass.java b/src/main/java/com/android/tools/r8/ir/code/InitClass.java
index d24dce8..22e4c4e 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InitClass.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InitClass.java
@@ -94,13 +94,17 @@
@Override
public boolean instructionInstanceCanThrow(AppView<?> appView, ProgramMethod context) {
+ // We only use InitClass instructions in R8.
+ assert appView.enableWholeProgramOptimizations();
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
DexClass definition = appView.definitionFor(clazz);
// * Check that the class is present.
if (definition == null) {
return true;
}
// * Check that the class is accessible.
- if (AccessControl.isClassAccessible(definition, context, appView).isPossiblyFalse()) {
+ if (AccessControl.isClassAccessible(definition, context, appViewWithLiveness)
+ .isPossiblyFalse()) {
return true;
}
if (clazz.classInitializationMayHaveSideEffects(
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
index 314317e..063592f 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeMultiNewArray.java
@@ -18,6 +18,7 @@
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.LongInterval;
import java.util.List;
@@ -133,6 +134,9 @@
return true;
}
+ assert appView.appInfo().hasLiveness();
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+
// Check if the type is guaranteed to be present.
DexClass clazz = appView.definitionFor(baseType);
if (clazz == null) {
@@ -145,7 +149,7 @@
}
// Check if the type is guaranteed to be accessible.
- if (AccessControl.isClassAccessible(clazz, context, appView).isPossiblyFalse()) {
+ if (AccessControl.isClassAccessible(clazz, context, appViewWithLiveness).isPossiblyFalse()) {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
index 2783471..25a4b47 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InvokeNewArray.java
@@ -19,6 +19,7 @@
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import java.util.List;
public class InvokeNewArray extends Invoke {
@@ -160,6 +161,9 @@
return true;
}
+ assert appView.appInfo().hasLiveness();
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+
// Check if the type is guaranteed to be present.
DexClass clazz = appView.definitionFor(baseType);
if (clazz == null) {
@@ -173,7 +177,7 @@
}
// Check if the type is guaranteed to be accessible.
- if (AccessControl.isClassAccessible(clazz, context, appView).isPossiblyFalse()) {
+ if (AccessControl.isClassAccessible(clazz, context, appViewWithLiveness).isPossiblyFalse()) {
return true;
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
index 3b8fc7f..ff7a054 100644
--- a/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/ir/code/NewInstance.java
@@ -169,7 +169,8 @@
}
// Verify that the instruction does not lead to an IllegalAccessError.
- if (AccessControl.isClassAccessible(definition, context, appView).isPossiblyFalse()) {
+ if (AccessControl.isClassAccessible(definition, context, appViewWithLiveness)
+ .isPossiblyFalse()) {
return true;
}
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 5107d27..605f698 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
@@ -3,7 +3,6 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.conversion;
-import static com.android.tools.r8.graph.DexAnnotation.readAnnotationSynthesizedClassMap;
import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.ExcludeDexResources;
import static com.android.tools.r8.ir.desugar.InterfaceMethodRewriter.Flavor.IncludeAllResources;
@@ -13,7 +12,6 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -90,7 +88,6 @@
import com.android.tools.r8.position.MethodPosition;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.LibraryMethodOverrideAnalysis;
-import com.android.tools.r8.shaking.MainDexClasses;
import com.android.tools.r8.shaking.MainDexTracingResult;
import com.android.tools.r8.utils.Action;
import com.android.tools.r8.utils.CfgPrinter;
@@ -105,22 +102,16 @@
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
import com.google.common.base.Suppliers;
-import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ListMultimap;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
-import java.util.Map;
import java.util.Set;
-import java.util.TreeSet;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
-import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Collectors;
@@ -237,8 +228,8 @@
this.desugaredLibraryAPIConverter =
new DesugaredLibraryAPIConverter(appView, Mode.GENERATE_CALLBACKS_AND_WRAPPERS);
this.backportedMethodRewriter =
- options.testing.forceLibBackportsInL8CfToCf
- ? new BackportedMethodRewriter(appView, this)
+ options.cfToCfDesugar || options.testing.forceLibBackportsInL8CfToCf
+ ? new BackportedMethodRewriter(appView)
: null;
this.twrCloseResourceRewriter = null;
this.lambdaMerger = null;
@@ -276,7 +267,7 @@
((options.desugarState == DesugarState.ON) && enableTwrCloseResourceDesugaring())
? new TwrCloseResourceRewriter(appView, this)
: null;
- this.backportedMethodRewriter = new BackportedMethodRewriter(appView, this);
+ this.backportedMethodRewriter = new BackportedMethodRewriter(appView);
this.desugaredLibraryRetargeter =
options.desugaredLibraryConfiguration.getRetargetCoreLibMember().isEmpty()
? null
@@ -445,10 +436,10 @@
}
}
- private void synthesizeJava8UtilityClass(
- Builder<?> builder, ExecutorService executorService) throws ExecutionException {
+ private void processSynthesizedJava8UtilityClasses(ExecutorService executorService)
+ throws ExecutionException {
if (backportedMethodRewriter != null) {
- backportedMethodRewriter.synthesizeUtilityClasses(builder, executorService);
+ backportedMethodRewriter.processSynthesizedClasses(this, executorService);
}
}
@@ -459,10 +450,10 @@
}
}
- private void synthesizeEnumUnboxingUtilityMethods(
- Builder<?> builder, ExecutorService executorService) throws ExecutionException {
+ private void synthesizeEnumUnboxingUtilityMethods(ExecutorService executorService)
+ throws ExecutionException {
if (enumUnboxer != null) {
- enumUnboxer.synthesizeUtilityMethods(builder, this, executorService);
+ enumUnboxer.synthesizeUtilityMethods(this, executorService);
}
}
@@ -489,96 +480,19 @@
synthesizeLambdaClasses(builder, executor);
desugarInterfaceMethods(builder, ExcludeDexResources, executor);
synthesizeTwrCloseResourceUtilityClass(builder, executor);
- synthesizeJava8UtilityClass(builder, executor);
+ processSynthesizedJava8UtilityClasses(executor);
synthesizeRetargetClass(builder, executor);
processCovariantReturnTypeAnnotations(builder);
generateDesugaredLibraryAPIWrappers(builder, executor);
- handleSynthesizedClassMapping(appView, builder);
timing.end();
DexApplication app = builder.build();
appView.setAppInfo(
new AppInfo(
- app,
- appView.appInfo().getMainDexClasses(),
- appView.appInfo().getSyntheticItems().commit(app)));
- }
-
- private void handleSynthesizedClassMapping(AppView<?> appView, Builder<?> builder) {
- if (options.intermediate) {
- updateSynthesizedClassMapping(builder);
- }
-
- updateMainDexListWithSynthesizedClassMap(appView, builder);
-
- if (!options.intermediate) {
- clearSynthesizedClassMapping(builder);
- }
- }
-
- private void updateMainDexListWithSynthesizedClassMap(AppView<?> appView, Builder<?> builder) {
- MainDexClasses mainDexClasses = appView.appInfo().getMainDexClasses();
- if (mainDexClasses.isEmpty()) {
- return;
- }
- Map<DexType, DexProgramClass> programClasses =
- builder.getProgramClasses().stream()
- .collect(Collectors.toMap(programClass -> programClass.type, Function.identity()));
- List<DexProgramClass> newMainDexClasses = new ArrayList<>();
- mainDexClasses.forEach(
- mainDexClass -> {
- DexProgramClass definition = programClasses.get(mainDexClass);
- if (definition == null) {
- return;
- }
- Iterable<DexType> syntheticTypes =
- readAnnotationSynthesizedClassMap(definition, appView.dexItemFactory());
- for (DexType syntheticType : syntheticTypes) {
- DexProgramClass syntheticClass = programClasses.get(syntheticType);
- if (syntheticClass != null) {
- newMainDexClasses.add(syntheticClass);
- }
- }
- });
- mainDexClasses.addAll(newMainDexClasses);
- }
-
- private void clearSynthesizedClassMapping(Builder<?> builder) {
- for (DexProgramClass clazz : builder.getProgramClasses()) {
- clazz.setAnnotations(
- clazz.annotations().getWithout(builder.dexItemFactory.annotationSynthesizedClassMap));
- }
- }
-
- private void updateSynthesizedClassMapping(Builder<?> builder) {
- ListMultimap<DexProgramClass, DexProgramClass> originalToSynthesized =
- ArrayListMultimap.create();
- for (DexProgramClass synthesized : builder.getSynthesizedClasses()) {
- for (DexProgramClass original : synthesized.getSynthesizedFrom()) {
- originalToSynthesized.put(original, synthesized);
- }
- }
-
- for (Map.Entry<DexProgramClass, Collection<DexProgramClass>> entry :
- originalToSynthesized.asMap().entrySet()) {
- DexProgramClass original = entry.getKey();
- // Use a tree set to make sure that we have an ordering on the types.
- // These types are put in an array in annotations in the output and we
- // need a consistent ordering on them.
- TreeSet<DexType> synthesized = new TreeSet<>(DexType::slowCompareTo);
- entry.getValue()
- .stream()
- .map(dexProgramClass -> dexProgramClass.type)
- .forEach(synthesized::add);
- synthesized.addAll(readAnnotationSynthesizedClassMap(original, builder.dexItemFactory));
-
- DexAnnotation updatedAnnotation =
- DexAnnotation.createAnnotationSynthesizedClassMap(synthesized, builder.dexItemFactory);
-
- original.setAnnotations(original.annotations().getWithAddedOrReplaced(updatedAnnotation));
- }
+ appView.appInfo().getSyntheticItems().commit(app),
+ appView.appInfo().getMainDexClasses()));
}
private void convertMethods(DexProgramClass clazz) {
@@ -675,16 +589,9 @@
executorService);
}
- public DexApplication optimize() throws ExecutionException {
- ExecutorService executor = Executors.newSingleThreadExecutor();
- try {
- return optimize(executor);
- } finally {
- executor.shutdown();
- }
- }
-
- public DexApplication optimize(ExecutorService executorService) throws ExecutionException {
+ public DexApplication optimize(
+ AppView<AppInfoWithLiveness> appView, ExecutorService executorService)
+ throws ExecutionException {
DexApplication application = appView.appInfo().app();
computeReachabilitySensitivity(application);
@@ -804,10 +711,9 @@
printPhase("Utility classes synthesis");
synthesizeTwrCloseResourceUtilityClass(builder, executorService);
- synthesizeJava8UtilityClass(builder, executorService);
+ processSynthesizedJava8UtilityClasses(executorService);
synthesizeRetargetClass(builder, executorService);
- handleSynthesizedClassMapping(appView, builder);
- synthesizeEnumUnboxingUtilityMethods(builder, executorService);
+ synthesizeEnumUnboxingUtilityMethods(executorService);
printPhase("Lambda merging finalization");
// TODO(b/127694949): Adapt to PostOptimization.
@@ -885,14 +791,20 @@
// Assure that no more optimization feedback left after post processing.
assert feedback.noUpdatesLeft();
-
- // Check if what we've added to the application builder as synthesized classes are same as
- // what we've added and used through AppInfo.
- assert appView.appInfo().synthesizedClasses().containsAll(builder.getSynthesizedClasses())
- && builder.getSynthesizedClasses().containsAll(appView.appInfo().synthesizedClasses());
+ assert checkLegacySyntheticsAreInBuilder(appView, builder);
return builder.build();
}
+ private boolean checkLegacySyntheticsAreInBuilder(
+ AppView<AppInfoWithLiveness> appView, Builder<?> builder) {
+ Collection<DexProgramClass> inAppInfo =
+ appView.appInfo().getSyntheticItems().getLegacyPendingClasses();
+ Collection<DexProgramClass> inBuilder = builder.getSynthesizedClasses();
+ assert inAppInfo.containsAll(inBuilder);
+ assert inBuilder.containsAll(inAppInfo);
+ return true;
+ }
+
private void waveStart(ProgramMethodSet wave) {
onWaveDoneActions = Collections.synchronizedList(new ArrayList<>());
}
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 5c08f1f..8cc0ffa 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
@@ -7,27 +7,17 @@
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.Code;
-import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
-import com.android.tools.r8.graph.DexApplication.Builder;
-import com.android.tools.r8.graph.DexClass;
-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.MethodAccessFlags;
-import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.analysis.type.TypeAnalysis;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Instruction;
@@ -45,7 +35,6 @@
import com.android.tools.r8.ir.desugar.backports.NumericMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.ObjectsMethodRewrites;
import com.android.tools.r8.ir.desugar.backports.OptionalMethodRewrites;
-import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
@@ -54,13 +43,13 @@
import com.google.common.collect.Sets;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
+import java.util.Queue;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.function.Consumer;
@@ -72,18 +61,13 @@
public static final String UTILITY_CLASS_NAME_PREFIX = "$r8$backportedMethods$utility";
private final AppView<?> appView;
- private final IRConverter converter;
- private final DexItemFactory factory;
private final RewritableMethods rewritableMethods;
private final boolean enabled;
- private final Set<DexType> holders = Sets.newConcurrentHashSet();
- private final Map<DexMethod, MethodProvider> methodProviders = new ConcurrentHashMap<>();
+ private final Queue<ProgramMethod> synthesizedMethods = new ConcurrentLinkedQueue<>();
- public BackportedMethodRewriter(AppView<?> appView, IRConverter converter) {
+ public BackportedMethodRewriter(AppView<?> appView) {
this.appView = appView;
- this.converter = converter;
- this.factory = appView.dexItemFactory();
this.rewritableMethods = new RewritableMethods(appView.options(), appView);
// Disable rewriting if there are no methods to rewrite or if the API level is higher than
// the highest known API level when the compiler is built. This ensures that when this is used
@@ -128,7 +112,6 @@
if (!enabled) {
return; // Nothing to do!
}
-
Set<Value> affectedValues = Sets.newIdentityHashSet();
InstructionListIterator iterator = code.instructionListIterator();
while (iterator.hasNext()) {
@@ -143,17 +126,11 @@
continue;
}
- MethodProvider provider = getMethodProviderOrNull(invoke.getInvokedMethod());
- if (provider == null) {
- continue;
- }
-
- provider.rewriteInvoke(invoke, iterator, code, appView, affectedValues);
-
- if (provider.requiresGenerationOfCode()) {
- DexMethod newMethod = provider.provideMethod(appView);
- methodProviders.putIfAbsent(newMethod, provider);
- holders.add(code.method().holder());
+ DexMethod invokedMethod = invoke.getInvokedMethod();
+ MethodProvider provider = getMethodProviderOrNull(invokedMethod);
+ if (provider != null) {
+ provider.rewriteInvoke(
+ invoke, iterator, code, appView, affectedValues, synthesizedMethods::add);
}
}
if (!affectedValues.isEmpty()) {
@@ -161,125 +138,15 @@
}
}
- private Collection<DexProgramClass> findSynthesizedFrom(Builder<?> builder, DexType holder) {
- for (DexProgramClass synthesizedClass : builder.getSynthesizedClasses()) {
- if (holder == synthesizedClass.getType()) {
- return synthesizedClass.getSynthesizedFrom();
- }
- }
- return null;
- }
-
- public static boolean hasRewrittenMethodPrefix(DexType clazz) {
- return clazz.descriptor.toString().contains(UTILITY_CLASS_NAME_PREFIX);
- }
-
- public void synthesizeUtilityClasses(Builder<?> builder, ExecutorService executorService)
+ public void processSynthesizedClasses(IRConverter converter, ExecutorService executor)
throws ExecutionException {
- if (!enabled) {
- return;
- }
- if (holders.isEmpty()) {
- return;
- }
- // Compute referencing classes ignoring references in-between utility classes.
- Set<DexProgramClass> referencingClasses = Sets.newConcurrentHashSet();
- for (DexType holder : holders) {
- DexClass definitionFor = appView.definitionFor(holder);
- if (definitionFor == null) {
- Collection<DexProgramClass> synthesizedFrom = findSynthesizedFrom(builder, holder);
- assert synthesizedFrom != null;
- referencingClasses.addAll(synthesizedFrom);
- } else {
- referencingClasses.add(definitionFor.asProgramClass());
+ while (!synthesizedMethods.isEmpty()) {
+ List<ProgramMethod> methods = new ArrayList<>(synthesizedMethods);
+ synthesizedMethods.clear();
+ for (ProgramMethod method : methods) {
+ converter.optimizeSynthesizedClass(method.getHolder(), executor);
}
}
-
- MethodAccessFlags flags =
- MethodAccessFlags.fromSharedAccessFlags(
- Constants.ACC_PUBLIC | Constants.ACC_STATIC | Constants.ACC_SYNTHETIC, false);
- ClassAccessFlags classAccessFlags =
- ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
- // Generate the utility classes in a loop since utility classes can require the
- // the creation of other utility classes.
- // Function multiplyExact(long, int) calls multiplyExact(long, long) for example.
- while (!methodProviders.isEmpty()) {
- DexMethod method = methodProviders.keySet().iterator().next();
- MethodProvider provider = methodProviders.remove(method);
- assert provider.requiresGenerationOfCode();
- // The utility class could have been synthesized, e.g., running R8 then D8,
- // or if already processed in this while loop.
- if (appView.definitionFor(method.holder) != null) {
- continue;
- }
- Code code = provider.generateTemplateMethod(appView.options(), method);
- DexEncodedMethod dexEncodedMethod =
- new DexEncodedMethod(
- method,
- flags,
- DexAnnotationSet.empty(),
- ParameterAnnotationsList.empty(),
- code,
- true);
- boolean addToMainDexClasses =
- appView.appInfo().getMainDexClasses().containsAnyOf(referencingClasses);
- DexProgramClass utilityClass =
- synthesizeClassWithUniqueMethod(
- builder,
- classAccessFlags,
- method.holder,
- dexEncodedMethod,
- "java8 methods utility class",
- addToMainDexClasses,
- appView);
- // The following may add elements to methodsProviders.
- converter.optimizeSynthesizedClass(utilityClass, executorService);
- }
- }
-
- static DexProgramClass synthesizeClassWithUniqueMethod(
- Builder<?> builder,
- ClassAccessFlags accessFlags,
- DexType type,
- DexEncodedMethod uniqueMethod,
- String origin,
- boolean addToMainDexClasses,
- AppView<?> appView) {
- DexItemFactory factory = appView.dexItemFactory();
- DexProgramClass newClass =
- new DexProgramClass(
- type,
- null,
- new SynthesizedOrigin(origin, BackportedMethodRewriter.class),
- accessFlags,
- factory.objectType,
- DexTypeList.empty(),
- null,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- uniqueMethod.isStatic()
- ? new DexEncodedMethod[] {uniqueMethod}
- : DexEncodedMethod.EMPTY_ARRAY,
- uniqueMethod.isStatic()
- ? DexEncodedMethod.EMPTY_ARRAY
- : new DexEncodedMethod[] {uniqueMethod},
- factory.getSkipNameValidationForTesting(),
- getChecksumSupplier(uniqueMethod, appView));
- appView.appInfo().addSynthesizedClass(newClass, addToMainDexClasses);
- builder.addSynthesizedClass(newClass);
- return newClass;
- }
-
- private static ChecksumSupplier getChecksumSupplier(DexEncodedMethod method, AppView<?> appView) {
- if (!appView.options().encodeChecksums) {
- return DexProgramClass::invalidChecksumRequest;
- }
- return c -> method.method.hashCode();
}
private MethodProvider getMethodProviderOrNull(DexMethod method) {
@@ -1433,13 +1300,8 @@
InstructionListIterator iterator,
IRCode code,
AppView<?> appView,
- Set<Value> affectedValues);
-
- public abstract DexMethod provideMethod(AppView<?> appView);
-
- public abstract Code generateTemplateMethod(InternalOptions options, DexMethod method);
-
- public abstract boolean requiresGenerationOfCode();
+ Set<Value> affectedValues,
+ Consumer<ProgramMethod> registerSynthesizedMethod);
}
private static final class InvokeRewriter extends MethodProvider {
@@ -1457,32 +1319,17 @@
InstructionListIterator iterator,
IRCode code,
AppView<?> appView,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Consumer<ProgramMethod> registerSynthesizedMethod) {
rewriter.rewrite(invoke, iterator, appView.dexItemFactory(), affectedValues);
assert code.isConsistentSSA();
}
-
- @Override
- public boolean requiresGenerationOfCode() {
- return false;
- }
-
- @Override
- public DexMethod provideMethod(AppView<?> appView) {
- throw new Unreachable();
- }
-
- @Override
- public Code generateTemplateMethod(InternalOptions options, DexMethod method) {
- throw new Unreachable();
- }
}
private static class MethodGenerator extends MethodProvider {
private final TemplateMethodFactory factory;
private final String methodName;
- DexMethod generatedMethod;
MethodGenerator(DexMethod method, TemplateMethodFactory factory) {
this(method, factory, method.name.toString());
@@ -1500,44 +1347,39 @@
InstructionListIterator iterator,
IRCode code,
AppView<?> appView,
- Set<Value> affectedValues) {
+ Set<Value> affectedValues,
+ Consumer<ProgramMethod> registerSynthesizedMethod) {
+ ProgramMethod method =
+ appView
+ .getSyntheticItems()
+ .createMethod(
+ code.context().getHolder(),
+ appView.dexItemFactory(),
+ builder ->
+ builder
+ .setProto(getProto(appView.dexItemFactory()))
+ .setAccessFlags(
+ MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC
+ | Constants.ACC_STATIC
+ | Constants.ACC_SYNTHETIC,
+ false))
+ .setCode(
+ methodSig -> generateTemplateMethod(appView.options(), methodSig)));
+
iterator.replaceCurrentInstruction(
- new InvokeStatic(provideMethod(appView), invoke.outValue(), invoke.inValues()));
+ new InvokeStatic(method.getReference(), invoke.outValue(), invoke.inValues()));
+
+ registerSynthesizedMethod.accept(method);
}
- @Override
- public DexMethod provideMethod(AppView<?> appView) {
- if (generatedMethod != null) {
- return generatedMethod;
- }
- DexItemFactory factory = appView.dexItemFactory();
- String unqualifiedName = method.holder.getName();
- // Avoid duplicate class names between core lib dex file and program dex files.
- String descriptor =
- "L"
- + appView.options().synthesizedClassPrefix
- + UTILITY_CLASS_NAME_PREFIX
- + '$'
- + unqualifiedName
- + '$'
- + method.proto.parameters.size()
- + '$'
- + methodName
- + ';';
- DexType type = factory.createType(descriptor);
- generatedMethod = factory.createMethod(type, method.proto, method.name);
- return generatedMethod;
+ public DexProto getProto(DexItemFactory itemFactory) {
+ return method.proto;
}
- @Override
public Code generateTemplateMethod(InternalOptions options, DexMethod method) {
return factory.create(options, method);
}
-
- @Override
- public boolean requiresGenerationOfCode() {
- return true;
- }
}
// Specific subclass to transform virtual methods into static desugared methods.
@@ -1554,16 +1396,8 @@
}
@Override
- public DexMethod provideMethod(AppView<?> appView) {
- if (generatedMethod != null) {
- return generatedMethod;
- }
- super.provideMethod(appView);
- assert generatedMethod != null;
- DexProto newProto = appView.dexItemFactory().prependTypeToProto(receiverType, method.proto);
- generatedMethod =
- appView.dexItemFactory().createMethod(generatedMethod.holder, newProto, method.name);
- return generatedMethod;
+ public DexProto getProto(DexItemFactory itemFactory) {
+ return itemFactory.prependTypeToProto(receiverType, super.getProto(itemFactory));
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
index 5ce5bb8..5280f61 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryRetargeter.java
@@ -9,15 +9,19 @@
import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexAnnotationSet;
import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexClass;
+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.DexLibraryClass;
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.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ResolutionResult;
@@ -27,6 +31,7 @@
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
import com.google.common.collect.Maps;
@@ -85,6 +90,49 @@
appView.options().reporter.warning(warning);
}
+ private static void synthesizeClassWithUniqueMethod(
+ Builder<?> builder,
+ ClassAccessFlags accessFlags,
+ DexType type,
+ DexEncodedMethod uniqueMethod,
+ String origin,
+ AppView<?> appView) {
+ DexItemFactory factory = appView.dexItemFactory();
+ DexProgramClass newClass =
+ new DexProgramClass(
+ type,
+ null,
+ new SynthesizedOrigin(origin, BackportedMethodRewriter.class),
+ accessFlags,
+ factory.objectType,
+ DexTypeList.empty(),
+ null,
+ null,
+ Collections.emptyList(),
+ null,
+ Collections.emptyList(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ uniqueMethod.isStatic()
+ ? new DexEncodedMethod[] {uniqueMethod}
+ : DexEncodedMethod.EMPTY_ARRAY,
+ uniqueMethod.isStatic()
+ ? DexEncodedMethod.EMPTY_ARRAY
+ : new DexEncodedMethod[] {uniqueMethod},
+ factory.getSkipNameValidationForTesting(),
+ getChecksumSupplier(uniqueMethod, appView));
+ appView.appInfo().addSynthesizedClass(newClass, false);
+ builder.addSynthesizedClass(newClass);
+ }
+
+ private static ChecksumSupplier getChecksumSupplier(DexEncodedMethod method, AppView<?> appView) {
+ if (!appView.options().encodeChecksums) {
+ return DexProgramClass::invalidChecksumRequest;
+ }
+ return c -> method.method.hashCode();
+ }
+
// Used by the ListOfBackportedMethods utility.
void visit(Consumer<DexMethod> consumer) {
retargetLibraryMember.keySet().forEach(consumer);
@@ -363,25 +411,23 @@
DexType interfaceType = dispatchInterfaceTypeFor(emulatedDispatchMethod);
DexEncodedMethod itfMethod =
generateInterfaceDispatchMethod(emulatedDispatchMethod, interfaceType);
- BackportedMethodRewriter.synthesizeClassWithUniqueMethod(
+ synthesizeClassWithUniqueMethod(
builder,
itfAccessFlags,
interfaceType,
itfMethod,
"desugared library dispatch interface",
- false,
appView);
// Dispatch holder.
DexType holderType = dispatchHolderTypeFor(emulatedDispatchMethod);
DexEncodedMethod dispatchMethod =
generateHolderDispatchMethod(emulatedDispatchMethod, holderType, itfMethod.method);
- BackportedMethodRewriter.synthesizeClassWithUniqueMethod(
+ synthesizeClassWithUniqueMethod(
builder,
holderAccessFlags,
holderType,
dispatchMethod,
"desugared library dispatch class",
- false,
appView);
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
index aa15050..7f697a9 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceMethodRewriter.java
@@ -239,11 +239,11 @@
if (instruction.isInvokeStatic()) {
InvokeStatic invokeStatic = instruction.asInvokeStatic();
DexMethod method = invokeStatic.getInvokedMethod();
- DexClass clazz = appInfo.definitionFor(method.holder);
- if (BackportedMethodRewriter.hasRewrittenMethodPrefix(method.holder)) {
+ if (appView.getSyntheticItems().isPendingSynthetic(method.holder)) {
// We did not create this code yet, but it will not require rewriting.
continue;
}
+ DexClass clazz = appInfo.definitionFor(method.holder);
if (clazz == null) {
// NOTE: leave unchanged those calls to undefined targets. This may lead to runtime
// exception but we can not report it as error since it can also be the intended
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
index 104fc97..ecad620 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaClass.java
@@ -617,7 +617,7 @@
encodedMethod.getCode(),
true);
newMethod.copyMetadata(encodedMethod);
- rewriter.originalMethodSignatures.put(callTarget, encodedMethod.method);
+ rewriter.lensBuilder.move(encodedMethod.method, callTarget);
DexEncodedMethod.setDebugInfoWithFakeThisParameter(
newMethod.getCode(), callTarget.getArity(), appView);
@@ -689,7 +689,7 @@
encodedMethod.getCode(),
true);
newMethod.copyMetadata(encodedMethod);
- rewriter.originalMethodSignatures.put(callTarget, encodedMethod.method);
+ rewriter.lensBuilder.move(encodedMethod.method, callTarget);
return newMethod;
});
return new ProgramMethod(implMethodHolder, replacement);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
index dd7889d..fad4980 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/LambdaRewriter.java
@@ -7,11 +7,13 @@
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.DexField;
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.EnclosingMethodAttribute;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.graph.ProgramMethod;
@@ -31,8 +33,6 @@
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
import com.google.common.collect.BiMap;
-import com.google.common.collect.HashBiMap;
-import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import java.util.ArrayList;
@@ -63,7 +63,7 @@
final DexString instanceFieldName;
- final BiMap<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create();
+ final LambdaRewriterLens.Builder lensBuilder = LambdaRewriterLens.builder();
// Maps call sites seen so far to inferred lambda descriptor. It is intended
// to help avoid re-matching call sites we already seen. Note that same call
@@ -160,6 +160,7 @@
appView.appInfo().addSynthesizedClass(synthesizedClass, lambdaClass.addToMainDexList.get());
builder.addSynthesizedClass(synthesizedClass);
}
+ fixup();
optimizeSynthesizedClasses(converter, executorService);
}
@@ -345,34 +346,78 @@
return knownLambdaClasses;
}
- public NestedGraphLens buildMappingLens(AppView<?> appView) {
- if (originalMethodSignatures.isEmpty()) {
+ public NestedGraphLens fixup() {
+ LambdaRewriterLens lens = lensBuilder.build(appView.graphLens(), appView.dexItemFactory());
+ if (lens == null) {
return null;
}
- return new LambdaRewriterLens(
- originalMethodSignatures, appView.graphLens(), appView.dexItemFactory());
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ EnclosingMethodAttribute enclosingMethod = clazz.getEnclosingMethodAttribute();
+ if (enclosingMethod != null) {
+ DexMethod mappedEnclosingMethod = lens.lookupMethod(enclosingMethod.getEnclosingMethod());
+ if (mappedEnclosingMethod != null
+ && mappedEnclosingMethod != enclosingMethod.getEnclosingMethod()) {
+ clazz.setEnclosingMethodAttribute(new EnclosingMethodAttribute(mappedEnclosingMethod));
+ }
+ }
+ }
+ ;
+ // Return lens without method map (but still retaining originalMethodSignatures), as the
+ // generated lambdas classes are generated with the an invoke to the new method, so no
+ // code rewriting is required.
+ return lens.withoutMethodMap();
}
static class LambdaRewriterLens extends NestedGraphLens {
- public LambdaRewriterLens(
+ LambdaRewriterLens(
+ Map<DexType, DexType> typeMap,
+ Map<DexMethod, DexMethod> methodMap,
+ Map<DexField, DexField> fieldMap,
+ BiMap<DexField, DexField> originalFieldSignatures,
BiMap<DexMethod, DexMethod> originalMethodSignatures,
- GraphLens graphLens,
- DexItemFactory factory) {
+ GraphLens previousLens,
+ DexItemFactory dexItemFactory) {
super(
- ImmutableMap.of(),
- ImmutableMap.of(),
- ImmutableMap.of(),
- null,
+ typeMap,
+ methodMap,
+ fieldMap,
+ originalFieldSignatures,
originalMethodSignatures,
- graphLens,
- factory);
+ previousLens,
+ dexItemFactory);
}
@Override
protected boolean isLegitimateToHaveEmptyMappings() {
return true;
}
+
+ private LambdaRewriterLens withoutMethodMap() {
+ methodMap.clear();
+ return this;
+ }
+
+ public static LambdaRewriterLens.Builder builder() {
+ return new LambdaRewriterLens.Builder();
+ }
+
+ public static class Builder extends NestedGraphLens.Builder {
+ public LambdaRewriterLens build(GraphLens previousLens, DexItemFactory dexItemFactory) {
+ if (typeMap.isEmpty() && methodMap.isEmpty() && fieldMap.isEmpty()) {
+ return null;
+ }
+ assert typeMap.isEmpty();
+ assert fieldMap.isEmpty();
+ return new LambdaRewriterLens(
+ typeMap,
+ methodMap,
+ fieldMap,
+ originalFieldSignatures,
+ originalMethodSignatures,
+ previousLens,
+ dexItemFactory);
+ }
+ }
}
}
-
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
index 996b8d8..70efbeb 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/CodeRewriter.java
@@ -1302,6 +1302,9 @@
return;
}
+ assert appView.appInfo().hasLiveness();
+ AppView<AppInfoWithLiveness> appViewWithLiveness = appView.withLiveness();
+
if (!appView.options().testing.enableCheckCastAndInstanceOfRemoval) {
return;
}
@@ -1337,7 +1340,8 @@
if (current.isCheckCast()) {
boolean hasPhiUsers = current.outValue().hasPhiUsers();
RemoveCheckCastInstructionIfTrivialResult removeResult =
- removeCheckCastInstructionIfTrivial(current.asCheckCast(), it, code, affectedValues);
+ removeCheckCastInstructionIfTrivial(
+ appViewWithLiveness, current.asCheckCast(), it, code, affectedValues);
if (removeResult != RemoveCheckCastInstructionIfTrivialResult.NO_REMOVALS) {
assert removeResult == RemoveCheckCastInstructionIfTrivialResult.REMOVED_CAST_DO_NARROW;
needToRemoveTrivialPhis |= hasPhiUsers;
@@ -1346,7 +1350,8 @@
}
} else if (current.isInstanceOf()) {
boolean hasPhiUsers = current.outValue().hasPhiUsers();
- if (removeInstanceOfInstructionIfTrivial(current.asInstanceOf(), it, code)) {
+ if (removeInstanceOfInstructionIfTrivial(
+ appViewWithLiveness, current.asInstanceOf(), it, code)) {
needToRemoveTrivialPhis |= hasPhiUsers;
}
}
@@ -1368,7 +1373,11 @@
// Returns true if the given check-cast instruction was removed.
private RemoveCheckCastInstructionIfTrivialResult removeCheckCastInstructionIfTrivial(
- CheckCast checkCast, InstructionListIterator it, IRCode code, Set<Value> affectedValues) {
+ AppView<AppInfoWithLiveness> appViewWithLiveness,
+ CheckCast checkCast,
+ InstructionListIterator it,
+ IRCode code,
+ Set<Value> affectedValues) {
Value inValue = checkCast.object();
Value outValue = checkCast.outValue();
DexType castType = checkCast.getType();
@@ -1380,7 +1389,7 @@
if (baseCastType.isClassType()) {
DexClass baseCastClass = appView.definitionFor(baseCastType);
if (baseCastClass == null
- || AccessControl.isClassAccessible(baseCastClass, code.context(), appView)
+ || AccessControl.isClassAccessible(baseCastClass, code.context(), appViewWithLiveness)
.isPossiblyFalse()) {
return RemoveCheckCastInstructionIfTrivialResult.NO_REMOVALS;
}
@@ -1436,7 +1445,10 @@
// Returns true if the given instance-of instruction was removed.
private boolean removeInstanceOfInstructionIfTrivial(
- InstanceOf instanceOf, InstructionListIterator it, IRCode code) {
+ AppView<AppInfoWithLiveness> appViewWithLiveness,
+ InstanceOf instanceOf,
+ InstructionListIterator it,
+ IRCode code) {
ProgramMethod context = code.context();
// If the instance-of type is not accessible in the current context, we should not remove the
@@ -1445,7 +1457,8 @@
if (instanceOfBaseType.isClassType()) {
DexClass instanceOfClass = appView.definitionFor(instanceOfBaseType);
if (instanceOfClass == null
- || AccessControl.isClassAccessible(instanceOfClass, context, appView).isPossiblyFalse()) {
+ || AccessControl.isClassAccessible(instanceOfClass, context, appViewWithLiveness)
+ .isPossiblyFalse()) {
return false;
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
index cbb86df..7a5dce9 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/DefaultInliningOracle.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.ir.optimize.inliner.InlinerUtils.collectAllMonitorEnterValues;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.Code;
import com.android.tools.r8.graph.DexEncodedField;
@@ -151,17 +152,16 @@
return false;
}
- InternalOptions options = appView.options();
- if (options.featureSplitConfiguration != null
- && !options.featureSplitConfiguration.inSameFeatureOrBothInBase(singleTarget, method)) {
+ ClassToFeatureSplitMap classToFeatureSplitMap = appView.appInfo().getClassToFeatureSplitMap();
+ if (!classToFeatureSplitMap.isInSameFeatureOrBothInBase(singleTarget, method)) {
// Still allow inlining if we inline from the base into a feature.
- if (!options.featureSplitConfiguration.isInBase(singleTarget.getHolder())) {
+ if (!classToFeatureSplitMap.isInBase(singleTarget.getHolder())) {
whyAreYouNotInliningReporter.reportInliningAcrossFeatureSplit();
return false;
}
}
- Set<Reason> validInliningReasons = options.testing.validInliningReasons;
+ Set<Reason> validInliningReasons = appView.options().testing.validInliningReasons;
if (validInliningReasons != null && !validInliningReasons.contains(reason)) {
whyAreYouNotInliningReporter.reportInvalidInliningReason(reason, validInliningReasons);
return false;
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
index 611a249..a36f313 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/Inliner.java
@@ -997,8 +997,8 @@
AccessControl.isMethodAccessible(
singleTarget.getDefinition(),
singleTarget.getHolder().asDexClass(),
- context.getHolder(),
- appView.withClassHierarchy().appInfo());
+ context,
+ appView);
if (!methodAccessible.isTrue()) {
continue;
}
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 7287edd..655ee2f 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
@@ -1284,8 +1284,7 @@
code -> {
ProgramMethod context = code.context();
assert !context.getDefinition().getCode().isOutlineCode();
- if (appView.options().featureSplitConfiguration != null
- && appView.options().featureSplitConfiguration.isInFeature(context.getHolder())) {
+ if (appView.appInfo().getClassToFeatureSplitMap().isInFeature(context.getHolder())) {
return;
}
for (BasicBlock block : code.blocks) {
@@ -1304,8 +1303,7 @@
public void identifyOutlineSites(IRCode code) {
ProgramMethod context = code.context();
assert !context.getDefinition().getCode().isOutlineCode();
- assert appView.options().featureSplitConfiguration == null
- || !appView.options().featureSplitConfiguration.isInFeature(context.getHolder());
+ assert !appView.appInfo().getClassToFeatureSplitMap().isInFeature(context.getHolder());
for (BasicBlock block : code.blocks) {
new OutlineSiteIdentifier(context, block).process();
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
index fd270a4..f9f4d58 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ReflectionOptimizer.java
@@ -196,8 +196,7 @@
// Don't allow the instantiated class to be in a feature, if it is, we can get a
// NoClassDefFoundError from dalvik/art.
if (baseClazz.isProgramClass()
- && appView.options().featureSplitConfiguration != null
- && appView.options().featureSplitConfiguration.isInFeature(baseClazz.asProgramClass())) {
+ && appView.appInfo().getClassToFeatureSplitMap().isInFeature(baseClazz.asProgramClass())) {
return null;
}
// Make sure the (base) type is visible.
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
index f1bcf3e..b1fcc81 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/ServiceLoaderRewriter.java
@@ -74,9 +74,9 @@
private AtomicReference<DexProgramClass> synthesizedClass = new AtomicReference<>();
- private final AppView<? extends AppInfoWithLiveness> appView;
+ private final AppView<AppInfoWithLiveness> appView;
- public ServiceLoaderRewriter(AppView<? extends AppInfoWithLiveness> appView) {
+ public ServiceLoaderRewriter(AppView<AppInfoWithLiveness> appView) {
this.appView = appView;
}
@@ -133,7 +133,9 @@
}
// Check that we are not service loading anything from a feature into base.
- if (appView.appServices().hasServiceImplementationsInFeature(constClass.getValue())) {
+ if (appView
+ .appServices()
+ .hasServiceImplementationsInFeature(appView, constClass.getValue())) {
continue;
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
index 54b7f8d..d4adf44 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxer.java
@@ -4,18 +4,12 @@
package com.android.tools.r8.ir.optimize.enums;
-import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.ir.analysis.type.Nullability.definitelyNotNull;
-import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AccessFlags;
import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.ClassAccessFlags;
-import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
-import com.android.tools.r8.graph.DexClass.FieldSetter;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMember;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -23,22 +17,15 @@
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.DexProto;
-import com.android.tools.r8.graph.DexString;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexTypeList;
-import com.android.tools.r8.graph.DexValue.DexValueInt;
-import com.android.tools.r8.graph.DexValue.DexValueNull;
import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.ProgramPackageCollection;
import com.android.tools.r8.graph.ResolutionResult;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
-import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.analysis.type.ArrayTypeElement;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
@@ -54,17 +41,14 @@
import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.InstanceGet;
import com.android.tools.r8.ir.code.Instruction;
-import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.InvokeMethod;
import com.android.tools.r8.ir.code.InvokeStatic;
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.Opcodes;
import com.android.tools.r8.ir.code.Phi;
import com.android.tools.r8.ir.code.Value;
-import com.android.tools.r8.ir.conversion.CodeOptimization;
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.conversion.PostMethodProcessor;
-import com.android.tools.r8.ir.conversion.PostOptimization;
import com.android.tools.r8.ir.optimize.Inliner.Constraint;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldMappingData;
@@ -74,24 +58,16 @@
import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback.OptimizationInfoFixer;
import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackDelayed;
-import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.BooleanUtils;
-import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import com.google.common.collect.BiMap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
import java.util.IdentityHashMap;
-import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -99,16 +75,15 @@
import java.util.concurrent.ExecutorService;
import java.util.function.Predicate;
-public class EnumUnboxer implements PostOptimization {
+public class EnumUnboxer {
private final AppView<AppInfoWithLiveness> appView;
private final DexItemFactory factory;
// Map the enum candidates with their dependencies, i.e., the methods to reprocess for the given
// enum if the optimization eventually decides to unbox it.
- private final Map<DexType, ProgramMethodSet> enumsUnboxingCandidates;
- private final Map<DexType, Set<DexField>> requiredEnumInstanceFieldData =
- new ConcurrentHashMap<>();
- private final Set<DexProgramClass> enumsToUnboxWithPackageRequirement = Sets.newIdentityHashSet();
+ private final EnumUnboxingCandidateInfoCollection enumUnboxingCandidatesInfo;
+ private final ProgramPackageCollection enumsToUnboxWithPackageRequirement =
+ ProgramPackageCollection.createEmpty();
private EnumUnboxingRewriter enumUnboxerRewriter;
@@ -126,19 +101,13 @@
debugLogs = null;
}
assert !appView.options().debug;
- enumsUnboxingCandidates = new EnumUnboxingCandidateAnalysis(appView, this).findCandidates();
- }
-
- private void requiredEnumInstanceFieldData(DexType enumType, DexField field) {
- requiredEnumInstanceFieldData
- .computeIfAbsent(enumType, ignored -> Sets.newConcurrentHashSet())
- .add(field);
+ enumUnboxingCandidatesInfo = new EnumUnboxingCandidateAnalysis(appView, this).findCandidates();
}
private void markEnumAsUnboxable(Reason reason, DexProgramClass enumClass) {
assert enumClass.isEnum();
reportFailure(enumClass.type, reason);
- enumsUnboxingCandidates.remove(enumClass.type);
+ enumUnboxingCandidatesInfo.removeCandidate(enumClass.type);
}
private DexProgramClass getEnumUnboxingCandidateOrNull(TypeElement lattice) {
@@ -156,10 +125,7 @@
}
private DexProgramClass getEnumUnboxingCandidateOrNull(DexType type) {
- if (!enumsUnboxingCandidates.containsKey(type)) {
- return null;
- }
- return appView.definitionForProgramType(type);
+ return enumUnboxingCandidatesInfo.getCandidateClassOrNull(type);
}
public void analyzeEnums(IRCode code) {
@@ -222,12 +188,7 @@
}
if (!eligibleEnums.isEmpty()) {
for (DexType eligibleEnum : eligibleEnums) {
- ProgramMethodSet dependencies = enumsUnboxingCandidates.get(eligibleEnum);
- // If dependencies is null, it means the enum is not eligible (It has been marked as
- // unboxable by this thread or another one), so we do not need to record dependencies.
- if (dependencies != null) {
- dependencies.add(code.context());
- }
+ enumUnboxingCandidatesInfo.addMethodDependency(eligibleEnum, code.context());
}
}
}
@@ -289,7 +250,7 @@
// - as a receiver for a name method, to allow unboxing of:
// MyEnum.class.getName();
DexType enumType = constClass.getValue();
- if (!enumsUnboxingCandidates.containsKey(enumType)) {
+ if (!enumUnboxingCandidatesInfo.isCandidate(enumType)) {
return;
}
if (constClass.outValue() == null) {
@@ -314,10 +275,15 @@
}
// The name data is required for the correct mapping from the enum name to the ordinal in the
// valueOf utility method.
- requiredEnumInstanceFieldData(enumType, factory.enumMembers.nameField);
+ addRequiredNameData(enumType);
eligibleEnums.add(enumType);
}
+ private void addRequiredNameData(DexType enumType) {
+ enumUnboxingCandidatesInfo.addRequiredEnumInstanceFieldData(
+ enumType, factory.enumMembers.nameField);
+ }
+
private boolean isUnboxableNameMethod(DexMethod method) {
return method == factory.classMethods.getName
|| method == factory.classMethods.getCanonicalName
@@ -330,7 +296,7 @@
InvokeMethod invokeMethod = use.asInvokeMethod();
DexMethod invokedMethod = invokeMethod.getInvokedMethod();
for (DexType paramType : invokedMethod.proto.parameters.values) {
- if (enumsUnboxingCandidates.containsKey(paramType)) {
+ if (enumUnboxingCandidatesInfo.isCandidate(paramType)) {
eligibleEnums.add(paramType);
}
}
@@ -342,12 +308,12 @@
}
} else if (use.isFieldPut()) {
DexType type = use.asFieldInstruction().getField().type;
- if (enumsUnboxingCandidates.containsKey(type)) {
+ if (enumUnboxingCandidatesInfo.isCandidate(type)) {
eligibleEnums.add(type);
}
} else if (use.isReturn()) {
DexType returnType = code.method().method.proto.returnType;
- if (enumsUnboxingCandidates.containsKey(returnType)) {
+ if (enumUnboxingCandidatesInfo.isCandidate(returnType)) {
eligibleEnums.add(returnType);
}
}
@@ -379,22 +345,41 @@
OptimizationFeedbackDelayed feedback)
throws ExecutionException {
EnumInstanceFieldDataMap enumInstanceFieldDataMap = finishAnalysis();
- // At this point the enumsToUnbox are no longer candidates, they will all be unboxed.
- if (enumsUnboxingCandidates.isEmpty()) {
+ // At this point the enum unboxing candidates are no longer candidates, they will all be
+ // unboxed. We extract the now immutable enums to unbox information and clear the candidate
+ // info.
+ if (enumUnboxingCandidatesInfo.isEmpty()) {
return;
}
- ImmutableSet<DexType> enumsToUnbox = ImmutableSet.copyOf(this.enumsUnboxingCandidates.keySet());
+ ImmutableSet<DexType> enumsToUnbox = enumUnboxingCandidatesInfo.candidates();
+ ImmutableSet<DexProgramClass> enumClassesToUnbox =
+ enumUnboxingCandidatesInfo.candidateClasses();
+ ProgramMethodSet dependencies = enumUnboxingCandidatesInfo.allMethodDependencies();
+ enumUnboxingCandidatesInfo.clear();
// Update keep info on any of the enum methods of the removed classes.
- updateKeepInfo(enumsToUnbox);
- enumUnboxerRewriter = new EnumUnboxingRewriter(appView, enumsToUnbox, enumInstanceFieldDataMap);
+ updateKeepInfo(enumClassesToUnbox);
DirectMappedDexApplication.Builder appBuilder = appView.appInfo().app().asDirect().builder();
- Map<DexType, DexType> newMethodLocation = synthesizeUnboxedEnumsMethodsLocations(appBuilder);
+ UnboxedEnumMemberRelocator relocator =
+ UnboxedEnumMemberRelocator.builder(appView)
+ .synthesizeEnumUnboxingUtilityClasses(
+ enumClassesToUnbox, enumsToUnboxWithPackageRequirement, appBuilder)
+ .build();
+ enumUnboxerRewriter =
+ new EnumUnboxingRewriter(appView, enumsToUnbox, enumInstanceFieldDataMap, relocator);
NestedGraphLens enumUnboxingLens =
- new TreeFixer(enumsToUnbox).fixupTypeReferences(newMethodLocation);
+ new EnumUnboxingTreeFixer(appView, enumsToUnbox, relocator, enumUnboxerRewriter)
+ .fixupTypeReferences();
appView.setUnboxedEnums(enumUnboxerRewriter.getEnumsToUnbox());
GraphLens previousLens = appView.graphLens();
appView.rewriteWithLensAndApplication(enumUnboxingLens, appBuilder.build());
- // Update optimization info.
+ updateOptimizationInfos(executorService, feedback);
+ postBuilder.put(dependencies);
+ postBuilder.rewrittenWithLens(appView, previousLens);
+ }
+
+ private void updateOptimizationInfos(
+ ExecutorService executorService, OptimizationFeedbackDelayed feedback)
+ throws ExecutionException {
feedback.fixupOptimizationInfos(
appView,
executorService,
@@ -426,88 +411,22 @@
}
}
});
- postBuilder.put(this);
- postBuilder.rewrittenWithLens(appView, previousLens);
}
- // Some enums may have methods which require to stay in the current package for accessibility,
- // in this case we create another class than the enum unboxing utility class to host these
- // methods.
- private Map<DexType, DexType> synthesizeUnboxedEnumsMethodsLocations(
- DirectMappedDexApplication.Builder appBuilder) {
- if (enumsToUnboxWithPackageRequirement.isEmpty()) {
- return Collections.emptyMap();
- }
- Map<DexType, DexType> newMethodLocationMap = new IdentityHashMap<>();
- Map<String, DexProgramClass> packageToClassMap = new HashMap<>();
- for (DexProgramClass toUnbox : enumsToUnboxWithPackageRequirement) {
- String packageDescriptor = toUnbox.getType().getPackageDescriptor();
- DexProgramClass syntheticClass = packageToClassMap.get(packageDescriptor);
- if (syntheticClass == null) {
- syntheticClass = synthesizeUtilityClassInPackage(packageDescriptor, appBuilder);
- packageToClassMap.put(packageDescriptor, syntheticClass);
- }
- if (appView.appInfo().getMainDexClasses().contains(toUnbox)) {
- appView.appInfo().getMainDexClasses().add(syntheticClass);
- }
- newMethodLocationMap.put(toUnbox.getType(), syntheticClass.getType());
- }
- enumsToUnboxWithPackageRequirement.clear();
- return newMethodLocationMap;
- }
-
- private DexProgramClass synthesizeUtilityClassInPackage(
- String packageDescriptor, DirectMappedDexApplication.Builder appBuilder) {
- DexType type =
- factory.createType(
- "L"
- + packageDescriptor
- + "/"
- + EnumUnboxingRewriter.ENUM_UNBOXING_UTILITY_CLASS_NAME
- + ";");
- if (type == factory.enumUnboxingUtilityType) {
- return appView.definitionFor(type).asProgramClass();
- }
- DexProgramClass syntheticClass =
- new DexProgramClass(
- type,
- null,
- new SynthesizedOrigin("enum unboxing", EnumUnboxer.class),
- ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC),
- factory.objectType,
- DexTypeList.empty(),
- null,
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedMethod.EMPTY_ARRAY,
- DexEncodedMethod.EMPTY_ARRAY,
- factory.getSkipNameValidationForTesting(),
- DexProgramClass::checksumFromType);
- appBuilder.addSynthesizedClass(syntheticClass);
- appView.appInfo().addSynthesizedClass(syntheticClass, false);
- return syntheticClass;
- }
-
- private void updateKeepInfo(Set<DexType> enumsToUnbox) {
+ private void updateKeepInfo(Set<DexProgramClass> enumsToUnbox) {
appView
.appInfo()
.getKeepInfo()
.mutate(
keepInfo -> {
- for (DexType type : enumsToUnbox) {
- DexProgramClass clazz = asProgramClassOrNull(appView.definitionFor(type));
- assert !keepInfo.getClassInfo(clazz).isPinned();
- clazz.forEachProgramMethod(
+ for (DexProgramClass enumToUnbox : enumsToUnbox) {
+ assert !keepInfo.getClassInfo(enumToUnbox).isPinned();
+ enumToUnbox.forEachProgramMethod(
method -> {
keepInfo.unsafeAllowMinificationOfMethod(method);
keepInfo.unsafeUnpinMethod(method);
});
- clazz.forEachProgramField(
+ enumToUnbox.forEachProgramField(
field -> {
keepInfo.unsafeAllowMinificationOfField(field);
keepInfo.unsafeUnpinField(field);
@@ -529,23 +448,19 @@
private EnumInstanceFieldDataMap analyzeFields() {
ImmutableMap.Builder<DexType, ImmutableMap<DexField, EnumInstanceFieldKnownData>> builder =
ImmutableMap.builder();
- requiredEnumInstanceFieldData.forEach(
- (enumType, fields) -> {
+ enumUnboxingCandidatesInfo.forEachCandidateAndRequiredInstanceFieldData(
+ (enumClass, fields) -> {
ImmutableMap.Builder<DexField, EnumInstanceFieldKnownData> typeBuilder =
ImmutableMap.builder();
- if (enumsUnboxingCandidates.containsKey(enumType)) {
- DexProgramClass enumClass = appView.definitionFor(enumType).asProgramClass();
- assert enumClass != null;
- for (DexField field : fields) {
- EnumInstanceFieldData enumInstanceFieldData = computeEnumFieldData(field, enumClass);
- if (enumInstanceFieldData.isUnknown()) {
- markEnumAsUnboxable(Reason.MISSING_INSTANCE_FIELD_DATA, enumClass);
- return;
- }
- typeBuilder.put(field, enumInstanceFieldData.asEnumFieldKnownData());
+ for (DexField field : fields) {
+ EnumInstanceFieldData enumInstanceFieldData = computeEnumFieldData(field, enumClass);
+ if (enumInstanceFieldData.isUnknown()) {
+ markEnumAsUnboxable(Reason.MISSING_INSTANCE_FIELD_DATA, enumClass);
+ return;
}
- builder.put(enumType, typeBuilder.build());
+ typeBuilder.put(field, enumInstanceFieldData.asEnumFieldKnownData());
}
+ builder.put(enumClass.type, typeBuilder.build());
});
return new EnumInstanceFieldDataMap(builder.build());
}
@@ -553,15 +468,15 @@
private void analyzeAccessibility() {
// Unboxing an enum will require to move its methods to a different class, which may impact
// accessibility. For a quick analysis we simply reuse the inliner analysis.
- for (DexType toUnbox : enumsUnboxingCandidates.keySet()) {
- DexProgramClass enumClass = appView.definitionFor(toUnbox).asProgramClass();
- Constraint classConstraint = analyzeAccessibilityInClass(enumClass);
- if (classConstraint == Constraint.NEVER) {
- markEnumAsUnboxable(Reason.ACCESSIBILITY, enumClass);
- } else if (classConstraint == Constraint.PACKAGE) {
- enumsToUnboxWithPackageRequirement.add(enumClass);
- }
- }
+ enumUnboxingCandidatesInfo.forEachCandidate(
+ enumClass -> {
+ Constraint classConstraint = analyzeAccessibilityInClass(enumClass);
+ if (classConstraint == Constraint.NEVER) {
+ markEnumAsUnboxable(Reason.ACCESSIBILITY, enumClass);
+ } else if (classConstraint == Constraint.PACKAGE) {
+ enumsToUnboxWithPackageRequirement.addProgramClass(enumClass);
+ }
+ });
}
private Constraint analyzeAccessibilityInClass(DexProgramClass enumClass) {
@@ -784,35 +699,33 @@
}
private void analyzeInitializers() {
- for (DexType toUnbox : enumsUnboxingCandidates.keySet()) {
- DexProgramClass enumClass = appView.definitionForProgramType(toUnbox);
- assert enumClass != null;
-
- boolean hasInstanceInitializer = false;
- for (DexEncodedMethod directMethod : enumClass.directMethods()) {
- if (directMethod.isInstanceInitializer()) {
- hasInstanceInitializer = true;
- if (directMethod
- .getOptimizationInfo()
- .getInstanceInitializerInfo()
- .mayHaveOtherSideEffectsThanInstanceFieldAssignments()) {
- markEnumAsUnboxable(Reason.INVALID_INIT, enumClass);
- break;
+ enumUnboxingCandidatesInfo.forEachCandidate(
+ enumClass -> {
+ boolean hasInstanceInitializer = false;
+ for (DexEncodedMethod directMethod : enumClass.directMethods()) {
+ if (directMethod.isInstanceInitializer()) {
+ hasInstanceInitializer = true;
+ if (directMethod
+ .getOptimizationInfo()
+ .getInstanceInitializerInfo()
+ .mayHaveOtherSideEffectsThanInstanceFieldAssignments()) {
+ markEnumAsUnboxable(Reason.INVALID_INIT, enumClass);
+ break;
+ }
+ }
}
- }
- }
- if (!hasInstanceInitializer) {
- // This case typically happens when a programmer uses EnumSet/EnumMap without using the
- // enum keep rules. The code is incorrect in this case (EnumSet/EnumMap won't work).
- // We bail out.
- markEnumAsUnboxable(Reason.NO_INIT, enumClass);
- continue;
- }
+ if (!hasInstanceInitializer) {
+ // This case typically happens when a programmer uses EnumSet/EnumMap without using the
+ // enum keep rules. The code is incorrect in this case (EnumSet/EnumMap won't work).
+ // We bail out.
+ markEnumAsUnboxable(Reason.NO_INIT, enumClass);
+ return;
+ }
- if (enumClass.classInitializationMayHaveSideEffects(appView)) {
- markEnumAsUnboxable(Reason.INVALID_CLINIT, enumClass);
- }
- }
+ if (enumClass.classInitializationMayHaveSideEffects(appView)) {
+ markEnumAsUnboxable(Reason.INVALID_CLINIT, enumClass);
+ }
+ });
}
private Reason instructionAllowEnumUnboxing(
@@ -834,7 +747,7 @@
return Reason.INVALID_INVOKE;
}
DexMethod singleTarget = encodedSingleTarget.method;
- DexClass dexClass = appView.definitionFor(singleTarget.holder);
+ DexClass dexClass = appView.definitionFor(singleTarget.holder, code.context());
if (dexClass == null) {
assert false;
return Reason.INVALID_INVOKE;
@@ -878,7 +791,7 @@
return Reason.ELIGIBLE;
}
if (singleTarget == factory.stringMembers.valueOf) {
- requiredEnumInstanceFieldData(enumClass.type, factory.enumMembers.nameField);
+ addRequiredNameData(enumClass.type);
return Reason.ELIGIBLE;
}
if (singleTarget == factory.objectMembers.getClass
@@ -900,14 +813,14 @@
} else if (singleTarget == factory.enumMembers.nameMethod
|| singleTarget == factory.enumMembers.toString) {
assert invokeMethod.asInvokeMethodWithReceiver().getReceiver() == enumValue;
- requiredEnumInstanceFieldData(enumClass.type, factory.enumMembers.nameField);
+ addRequiredNameData(enumClass.type);
return Reason.ELIGIBLE;
} else if (singleTarget == factory.enumMembers.ordinalMethod) {
return Reason.ELIGIBLE;
} else if (singleTarget == factory.enumMembers.hashCode) {
return Reason.ELIGIBLE;
} else if (singleTarget == factory.enumMembers.constructor) {
- // Enum constructor call is allowed only if first call of an enum initializer.
+ // Enum constructor call is allowed only if called from an enum initializer.
if (code.method().isInstanceInitializer() && code.method().holder() == enumClass.type) {
return Reason.ELIGIBLE;
}
@@ -924,7 +837,7 @@
if (field == null) {
return Reason.INVALID_FIELD_PUT;
}
- DexProgramClass dexClass = appView.definitionForProgramType(field.holder());
+ DexProgramClass dexClass = appView.programDefinitionFor(field.holder(), code.context());
if (dexClass == null) {
return Reason.INVALID_FIELD_PUT;
}
@@ -943,7 +856,7 @@
InstanceGet instanceGet = instruction.asInstanceGet();
assert instanceGet.getField().holder == enumClass.type;
DexField field = instanceGet.getField();
- requiredEnumInstanceFieldData(enumClass.type, field);
+ enumUnboxingCandidatesInfo.addRequiredEnumInstanceFieldData(enumClass.type, field);
return Reason.ELIGIBLE;
}
@@ -1112,12 +1025,13 @@
private void reportEnumsAnalysis() {
assert debugLogEnabled;
Reporter reporter = appView.options().reporter;
+ Set<DexType> candidates = enumUnboxingCandidatesInfo.candidates();
reporter.info(
new StringDiagnostic(
"Unboxed enums (Unboxing succeeded "
- + enumsUnboxingCandidates.size()
+ + candidates.size()
+ "): "
- + Arrays.toString(enumsUnboxingCandidates.keySet().toArray())));
+ + Arrays.toString(candidates.toArray())));
StringBuilder sb = new StringBuilder();
sb.append("Boxed enums (Unboxing failed ").append(debugLogs.size()).append("):\n");
for (DexType enumType : debugLogs.keySet()) {
@@ -1145,29 +1059,13 @@
return Sets.newIdentityHashSet();
}
- public void synthesizeUtilityMethods(
- Builder<?> builder, IRConverter converter, ExecutorService executorService)
+ public void synthesizeUtilityMethods(IRConverter converter, ExecutorService executorService)
throws ExecutionException {
if (enumUnboxerRewriter != null) {
- enumUnboxerRewriter.synthesizeEnumUnboxingUtilityMethods(builder, converter, executorService);
+ enumUnboxerRewriter.synthesizeEnumUnboxingUtilityMethods(converter, executorService);
}
}
- @Override
- public ProgramMethodSet methodsToRevisit() {
- ProgramMethodSet toReprocess = ProgramMethodSet.create();
- for (ProgramMethodSet methods : enumsUnboxingCandidates.values()) {
- toReprocess.addAll(methods);
- }
- return toReprocess;
- }
-
- @Override
- public Collection<CodeOptimization> codeOptimizationsForPostProcessing() {
- // Answers null so default optimization setup is performed.
- return null;
- }
-
public enum Reason {
ELIGIBLE,
ACCESSIBILITY,
@@ -1205,307 +1103,4 @@
ENUM_METHOD_CALLED_WITH_NULL_RECEIVER,
OTHER_UNSUPPORTED_INSTRUCTION;
}
-
- private class TreeFixer {
-
- private final Map<DexType, List<DexEncodedMethod>> unboxedEnumsMethods =
- new IdentityHashMap<>();
- private final EnumUnboxingLens.Builder lensBuilder = EnumUnboxingLens.builder();
- private final Set<DexType> enumsToUnbox;
-
- private TreeFixer(Set<DexType> enumsToUnbox) {
- this.enumsToUnbox = enumsToUnbox;
- }
-
- private NestedGraphLens fixupTypeReferences(Map<DexType, DexType> newMethodLocation) {
- assert enumUnboxerRewriter != null;
- // Fix all methods and fields using enums to unbox.
- for (DexProgramClass clazz : appView.appInfo().classes()) {
- if (enumsToUnbox.contains(clazz.type)) {
- // Clear the initializers and move the static methods to the new location.
- Set<DexEncodedMethod> methodsToRemove = Sets.newIdentityHashSet();
- clazz
- .methods()
- .forEach(
- m -> {
- if (m.isInitializer()) {
- clearEnumToUnboxMethod(m);
- } else {
- DexType newHolder =
- newMethodLocation.getOrDefault(
- clazz.type, factory.enumUnboxingUtilityType);
- List<DexEncodedMethod> movedMethods =
- unboxedEnumsMethods.computeIfAbsent(newHolder, k -> new ArrayList<>());
- movedMethods.add(fixupEncodedMethodToUtility(m, newHolder));
- methodsToRemove.add(m);
- }
- });
- clazz.getMethodCollection().removeMethods(methodsToRemove);
- } else {
- clazz.getMethodCollection().replaceMethods(this::fixupEncodedMethod);
- fixupFields(clazz.staticFields(), clazz::setStaticField);
- fixupFields(clazz.instanceFields(), clazz::setInstanceField);
- }
- }
- for (DexType toUnbox : enumsToUnbox) {
- lensBuilder.map(toUnbox, factory.intType);
- }
- DexProgramClass utilityClass =
- appView.definitionForProgramType(factory.enumUnboxingUtilityType);
- assert utilityClass != null : "Should have been synthesized upfront";
- unboxedEnumsMethods.forEach(
- (newHolderType, movedMethods) -> {
- DexProgramClass newHolderClass = appView.definitionFor(newHolderType).asProgramClass();
- newHolderClass.addDirectMethods(movedMethods);
- });
- return lensBuilder.build(factory, appView.graphLens(), enumsToUnbox);
- }
-
- private void clearEnumToUnboxMethod(DexEncodedMethod enumMethod) {
- // The compiler may have references to the enum methods, but such methods will be removed
- // and they cannot be reprocessed since their rewriting through the lensCodeRewriter/
- // enumUnboxerRewriter will generate invalid code.
- // To work around this problem we clear such methods, i.e., we replace the code object by
- // an empty throwing code object, so reprocessing won't take time and will be valid.
- enumMethod.setCode(enumMethod.buildEmptyThrowingCode(appView.options()), appView);
- }
-
- private DexEncodedMethod fixupEncodedMethodToUtility(
- DexEncodedMethod encodedMethod, DexType newHolder) {
- DexMethod method = encodedMethod.method;
- DexString newMethodName =
- factory.createString(
- enumUnboxerRewriter.compatibleName(method.holder)
- + "$"
- + (encodedMethod.isStatic() ? "s" : "v")
- + "$"
- + method.name.toString());
- DexProto proto =
- encodedMethod.isStatic() ? method.proto : factory.prependHolderToProto(method);
- DexMethod newMethod = factory.createMethod(newHolder, fixupProto(proto), newMethodName);
- assert appView.definitionFor(encodedMethod.holder()).lookupMethod(newMethod) == null;
- lensBuilder.move(method, encodedMethod.isStatic(), newMethod, true);
- encodedMethod.accessFlags.promoteToPublic();
- encodedMethod.accessFlags.promoteToStatic();
- encodedMethod.clearAnnotations();
- encodedMethod.clearParameterAnnotations();
- return encodedMethod.toTypeSubstitutedMethod(newMethod);
- }
-
- private DexEncodedMethod fixupEncodedMethod(DexEncodedMethod encodedMethod) {
- DexProto newProto = fixupProto(encodedMethod.proto());
- if (newProto == encodedMethod.proto()) {
- return encodedMethod;
- }
- assert !encodedMethod.isClassInitializer();
- // We add the $enumunboxing$ suffix to make sure we do not create a library override.
- String newMethodName =
- encodedMethod.getName().toString()
- + (encodedMethod.isNonPrivateVirtualMethod() ? "$enumunboxing$" : "");
- DexMethod newMethod = factory.createMethod(encodedMethod.holder(), newProto, newMethodName);
- newMethod = ensureUniqueMethod(encodedMethod, newMethod);
- int numberOfExtraNullParameters = newMethod.getArity() - encodedMethod.method.getArity();
- boolean isStatic = encodedMethod.isStatic();
- lensBuilder.move(
- encodedMethod.method, isStatic, newMethod, isStatic, numberOfExtraNullParameters);
- DexEncodedMethod newEncodedMethod = encodedMethod.toTypeSubstitutedMethod(newMethod);
- assert !encodedMethod.isLibraryMethodOverride().isTrue()
- : "Enum unboxing is changing the signature of a library override in a non unboxed class.";
- if (newEncodedMethod.isNonPrivateVirtualMethod()) {
- newEncodedMethod.setLibraryMethodOverride(OptionalBool.FALSE);
- }
- return newEncodedMethod;
- }
-
- private DexMethod ensureUniqueMethod(DexEncodedMethod encodedMethod, DexMethod newMethod) {
- DexClass holder = appView.definitionFor(encodedMethod.holder());
- assert holder != null;
- if (encodedMethod.isInstanceInitializer()) {
- while (holder.lookupMethod(newMethod) != null) {
- newMethod =
- factory.createMethod(
- newMethod.holder,
- factory.appendTypeToProto(newMethod.proto, factory.enumUnboxingUtilityType),
- newMethod.name);
- }
- } else {
- int index = 0;
- while (holder.lookupMethod(newMethod) != null) {
- newMethod =
- factory.createMethod(
- newMethod.holder,
- newMethod.proto,
- encodedMethod.getName().toString() + "$enumunboxing$" + index++);
- }
- }
- return newMethod;
- }
-
- private void fixupFields(List<DexEncodedField> fields, FieldSetter setter) {
- if (fields == null) {
- return;
- }
- for (int i = 0; i < fields.size(); i++) {
- DexEncodedField encodedField = fields.get(i);
- DexField field = encodedField.field;
- DexType newType = fixupType(field.type);
- if (newType != field.type) {
- DexField newField = factory.createField(field.holder, newType, field.name);
- lensBuilder.move(field, newField);
- DexEncodedField newEncodedField = encodedField.toTypeSubstitutedField(newField);
- setter.setField(i, newEncodedField);
- if (encodedField.isStatic() && encodedField.hasExplicitStaticValue()) {
- assert encodedField.getStaticValue() == DexValueNull.NULL;
- newEncodedField.setStaticValue(DexValueInt.DEFAULT);
- // TODO(b/150593449): Support conversion from DexValueEnum to DexValueInt.
- }
- }
- }
- }
-
- private DexProto fixupProto(DexProto proto) {
- DexType returnType = fixupType(proto.returnType);
- DexType[] arguments = fixupTypes(proto.parameters.values);
- return factory.createProto(returnType, arguments);
- }
-
- private DexType fixupType(DexType type) {
- if (type.isArrayType()) {
- DexType base = type.toBaseType(factory);
- DexType fixed = fixupType(base);
- if (base == fixed) {
- return type;
- }
- return type.replaceBaseType(fixed, factory);
- }
- if (type.isClassType() && enumsToUnbox.contains(type)) {
- DexType intType = factory.intType;
- lensBuilder.map(type, intType);
- return intType;
- }
- return type;
- }
-
- private DexType[] fixupTypes(DexType[] types) {
- DexType[] result = new DexType[types.length];
- for (int i = 0; i < result.length; i++) {
- result[i] = fixupType(types[i]);
- }
- return result;
- }
- }
-
- private static class EnumUnboxingLens extends NestedGraphLens {
-
- private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod;
- private final Set<DexType> unboxedEnums;
-
- EnumUnboxingLens(
- Map<DexType, DexType> typeMap,
- Map<DexMethod, DexMethod> methodMap,
- Map<DexField, DexField> fieldMap,
- BiMap<DexField, DexField> originalFieldSignatures,
- BiMap<DexMethod, DexMethod> originalMethodSignatures,
- GraphLens previousLens,
- DexItemFactory dexItemFactory,
- Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod,
- Set<DexType> unboxedEnums) {
- super(
- typeMap,
- methodMap,
- fieldMap,
- originalFieldSignatures,
- originalMethodSignatures,
- previousLens,
- dexItemFactory);
- this.prototypeChangesPerMethod = prototypeChangesPerMethod;
- this.unboxedEnums = unboxedEnums;
- }
-
- @Override
- protected RewrittenPrototypeDescription internalDescribePrototypeChanges(
- RewrittenPrototypeDescription prototypeChanges, DexMethod method) {
- // During the second IR processing enum unboxing is the only optimization rewriting
- // prototype description, if this does not hold, remove the assertion and merge
- // the two prototype changes.
- assert prototypeChanges.isEmpty();
- return prototypeChangesPerMethod.getOrDefault(method, RewrittenPrototypeDescription.none());
- }
-
- @Override
- protected Invoke.Type mapInvocationType(
- DexMethod newMethod, DexMethod originalMethod, Invoke.Type type) {
- if (unboxedEnums.contains(originalMethod.holder)) {
- // Methods moved from unboxed enums to the utility class are either static or statified.
- assert newMethod != originalMethod;
- return Invoke.Type.STATIC;
- }
- return type;
- }
-
- public static Builder builder() {
- return new Builder();
- }
-
- private static class Builder extends NestedGraphLens.Builder {
-
- private Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod =
- new IdentityHashMap<>();
-
- public void move(DexMethod from, boolean fromStatic, DexMethod to, boolean toStatic) {
- move(from, fromStatic, to, toStatic, 0);
- }
-
- public void move(
- DexMethod from,
- boolean fromStatic,
- DexMethod to,
- boolean toStatic,
- int numberOfExtraNullParameters) {
- super.move(from, to);
- int offsetDiff = 0;
- int toOffset = BooleanUtils.intValue(!toStatic);
- ArgumentInfoCollection.Builder builder = ArgumentInfoCollection.builder();
- if (fromStatic != toStatic) {
- assert toStatic;
- offsetDiff = 1;
- builder.addArgumentInfo(
- 0, new RewrittenTypeInfo(from.holder, to.proto.parameters.values[0]));
- }
- for (int i = 0; i < from.proto.parameters.size(); i++) {
- DexType fromType = from.proto.parameters.values[i];
- DexType toType = to.proto.parameters.values[i + offsetDiff];
- if (fromType != toType) {
- builder.addArgumentInfo(
- i + offsetDiff + toOffset, new RewrittenTypeInfo(fromType, toType));
- }
- }
- RewrittenTypeInfo returnInfo =
- from.proto.returnType == to.proto.returnType
- ? null
- : new RewrittenTypeInfo(from.proto.returnType, to.proto.returnType);
- prototypeChangesPerMethod.put(
- to,
- RewrittenPrototypeDescription.createForRewrittenTypes(returnInfo, builder.build())
- .withExtraUnusedNullParameters(numberOfExtraNullParameters));
- }
-
- public EnumUnboxingLens build(
- DexItemFactory dexItemFactory, GraphLens previousLens, Set<DexType> unboxedEnums) {
- if (typeMap.isEmpty() && methodMap.isEmpty() && fieldMap.isEmpty()) {
- return null;
- }
- return new EnumUnboxingLens(
- typeMap,
- methodMap,
- fieldMap,
- originalFieldSignatures,
- originalMethodSignatures,
- previousLens,
- dexItemFactory,
- ImmutableMap.copyOf(prototypeChangesPerMethod),
- ImmutableSet.copyOf(unboxedEnums));
- }
- }
- }
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
index b5a5b62..e0b6ff5 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateAnalysis.java
@@ -16,9 +16,6 @@
import com.android.tools.r8.ir.optimize.enums.EnumUnboxer.Reason;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.KeepInfoCollection;
-import com.android.tools.r8.utils.collections.ProgramMethodSet;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
class EnumUnboxingCandidateAnalysis {
@@ -30,7 +27,8 @@
private final AppView<AppInfoWithLiveness> appView;
private final EnumUnboxer enumUnboxer;
private final DexItemFactory factory;
- private Map<DexType, ProgramMethodSet> enumToUnboxCandidates = new ConcurrentHashMap<>();
+ private EnumUnboxingCandidateInfoCollection enumToUnboxCandidates =
+ new EnumUnboxingCandidateInfoCollection();
EnumUnboxingCandidateAnalysis(AppView<AppInfoWithLiveness> appView, EnumUnboxer enumUnboxer) {
this.appView = appView;
@@ -38,16 +36,16 @@
factory = appView.dexItemFactory();
}
- Map<DexType, ProgramMethodSet> findCandidates() {
+ EnumUnboxingCandidateInfoCollection findCandidates() {
for (DexProgramClass clazz : appView.appInfo().classes()) {
if (isEnumUnboxingCandidate(clazz)) {
- enumToUnboxCandidates.put(clazz.type, ProgramMethodSet.createConcurrent());
+ enumToUnboxCandidates.addCandidate(clazz);
}
}
removeEnumsInAnnotations();
removePinnedCandidates();
if (appView.options().protoShrinking().isProtoShrinkingEnabled()) {
- enumToUnboxCandidates.remove(appView.protoShrinker().references.methodToInvokeType);
+ enumToUnboxCandidates.removeCandidate(appView.protoShrinker().references.methodToInvokeType);
}
return enumToUnboxCandidates;
}
@@ -114,9 +112,9 @@
assert method.parameters().isEmpty()
|| appView.options().testing.allowInjectedAnnotationMethods;
DexType valueType = method.returnType().toBaseType(appView.dexItemFactory());
- if (enumToUnboxCandidates.containsKey(valueType)) {
+ if (enumToUnboxCandidates.isCandidate(valueType)) {
enumUnboxer.reportFailure(valueType, Reason.ANNOTATION);
- enumToUnboxCandidates.remove(valueType);
+ enumToUnboxCandidates.removeCandidate(valueType);
}
}
}
@@ -146,9 +144,9 @@
}
private void removePinnedCandidate(DexType type) {
- if (enumToUnboxCandidates.containsKey(type)) {
+ if (enumToUnboxCandidates.isCandidate(type)) {
enumUnboxer.reportFailure(type, Reason.PINNED);
- enumToUnboxCandidates.remove(type);
+ enumToUnboxCandidates.removeCandidate(type);
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java
new file mode 100644
index 0000000..947cc6d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingCandidateInfoCollection.java
@@ -0,0 +1,134 @@
+// Copyright (c) 2020, 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.ir.optimize.enums;
+
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
+public class EnumUnboxingCandidateInfoCollection {
+
+ private final Map<DexType, EnumUnboxingCandidateInfo> enumTypeToInfo = new ConcurrentHashMap<>();
+
+ public void addCandidate(DexProgramClass enumClass) {
+ assert !enumTypeToInfo.containsKey(enumClass.type);
+ enumTypeToInfo.put(enumClass.type, new EnumUnboxingCandidateInfo(enumClass));
+ }
+
+ public void removeCandidate(DexType enumType) {
+ enumTypeToInfo.remove(enumType);
+ }
+
+ public boolean isCandidate(DexType enumType) {
+ return enumTypeToInfo.containsKey(enumType);
+ }
+
+ public boolean isEmpty() {
+ return enumTypeToInfo.isEmpty();
+ }
+
+ public ImmutableSet<DexType> candidates() {
+ return ImmutableSet.copyOf(enumTypeToInfo.keySet());
+ }
+
+ public ImmutableSet<DexProgramClass> candidateClasses() {
+ ImmutableSet.Builder<DexProgramClass> builder = ImmutableSet.builder();
+ for (EnumUnboxingCandidateInfo info : enumTypeToInfo.values()) {
+ builder.add(info.getEnumClass());
+ }
+ return builder.build();
+ }
+
+ public DexProgramClass getCandidateClassOrNull(DexType enumType) {
+ EnumUnboxingCandidateInfo info = enumTypeToInfo.get(enumType);
+ if (info == null) {
+ return null;
+ }
+ return info.enumClass;
+ }
+
+ public ProgramMethodSet allMethodDependencies() {
+ ProgramMethodSet allMethodDependencies = ProgramMethodSet.create();
+ for (EnumUnboxingCandidateInfo info : enumTypeToInfo.values()) {
+ allMethodDependencies.addAll(info.methodDependencies);
+ }
+ return allMethodDependencies;
+ }
+
+ public void addMethodDependency(DexType enumType, ProgramMethod programMethod) {
+ // The enumType may be removed concurrently map from enumTypeToInfo. It means in that
+ // case the enum is no longer a candidate, and dependencies don't need to be recorded
+ // anymore.
+ EnumUnboxingCandidateInfo info = enumTypeToInfo.get(enumType);
+ if (info == null) {
+ return;
+ }
+ info.addMethodDependency(programMethod);
+ }
+
+ public void addRequiredEnumInstanceFieldData(DexType enumType, DexField field) {
+ // The enumType may be removed concurrently map from enumTypeToInfo. It means in that
+ // case the enum is no longer a candidate, and dependencies don't need to be recorded
+ // anymore.
+ EnumUnboxingCandidateInfo info = enumTypeToInfo.get(enumType);
+ if (info == null) {
+ return;
+ }
+ info.addRequiredInstanceFieldData(field);
+ }
+
+ public void forEachCandidate(Consumer<DexProgramClass> enumClassConsumer) {
+ enumTypeToInfo.values().forEach(info -> enumClassConsumer.accept(info.enumClass));
+ }
+
+ public void forEachCandidateAndRequiredInstanceFieldData(
+ BiConsumer<DexProgramClass, Set<DexField>> biConsumer) {
+ enumTypeToInfo
+ .values()
+ .forEach(
+ info -> biConsumer.accept(info.getEnumClass(), info.getRequiredInstanceFieldData()));
+ }
+
+ public void clear() {
+ enumTypeToInfo.clear();
+ }
+
+ private static class EnumUnboxingCandidateInfo {
+
+ private final DexProgramClass enumClass;
+ private final ProgramMethodSet methodDependencies = ProgramMethodSet.createConcurrent();
+ private final Set<DexField> requiredInstanceFieldData = Sets.newConcurrentHashSet();
+
+ public EnumUnboxingCandidateInfo(DexProgramClass enumClass) {
+ assert enumClass != null;
+ this.enumClass = enumClass;
+ }
+
+ public DexProgramClass getEnumClass() {
+ return enumClass;
+ }
+
+ public void addMethodDependency(ProgramMethod programMethod) {
+ methodDependencies.add(programMethod);
+ }
+
+ public void addRequiredInstanceFieldData(DexField field) {
+ requiredInstanceFieldData.add(field);
+ }
+
+ public Set<DexField> getRequiredInstanceFieldData() {
+ return requiredInstanceFieldData;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
new file mode 100644
index 0000000..869cb6e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingLens.java
@@ -0,0 +1,139 @@
+// Copyright (c) 2020, 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.ir.optimize.enums;
+
+import com.android.tools.r8.graph.DexField;
+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.graph.GraphLens;
+import com.android.tools.r8.graph.RewrittenPrototypeDescription;
+import com.android.tools.r8.ir.code.Invoke;
+import com.android.tools.r8.utils.BooleanUtils;
+import com.google.common.collect.BiMap;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+
+class EnumUnboxingLens extends GraphLens.NestedGraphLens {
+
+ private final Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod;
+ private final Set<DexType> unboxedEnums;
+
+ EnumUnboxingLens(
+ Map<DexType, DexType> typeMap,
+ Map<DexMethod, DexMethod> methodMap,
+ Map<DexField, DexField> fieldMap,
+ BiMap<DexField, DexField> originalFieldSignatures,
+ BiMap<DexMethod, DexMethod> originalMethodSignatures,
+ GraphLens previousLens,
+ DexItemFactory dexItemFactory,
+ Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod,
+ Set<DexType> unboxedEnums) {
+ super(
+ typeMap,
+ methodMap,
+ fieldMap,
+ originalFieldSignatures,
+ originalMethodSignatures,
+ previousLens,
+ dexItemFactory);
+ this.prototypeChangesPerMethod = prototypeChangesPerMethod;
+ this.unboxedEnums = unboxedEnums;
+ }
+
+ @Override
+ protected RewrittenPrototypeDescription internalDescribePrototypeChanges(
+ RewrittenPrototypeDescription prototypeChanges, DexMethod method) {
+ // During the second IR processing enum unboxing is the only optimization rewriting
+ // prototype description, if this does not hold, remove the assertion and merge
+ // the two prototype changes.
+ assert prototypeChanges.isEmpty();
+ return prototypeChangesPerMethod.getOrDefault(method, RewrittenPrototypeDescription.none());
+ }
+
+ @Override
+ protected Invoke.Type mapInvocationType(
+ DexMethod newMethod, DexMethod originalMethod, Invoke.Type type) {
+ if (unboxedEnums.contains(originalMethod.holder)) {
+ // Methods moved from unboxed enums to the utility class are either static or statified.
+ assert newMethod != originalMethod;
+ return Invoke.Type.STATIC;
+ }
+ return type;
+ }
+
+ public static Builder builder() {
+ return new Builder();
+ }
+
+ static class Builder extends NestedGraphLens.Builder {
+
+ private Map<DexMethod, RewrittenPrototypeDescription> prototypeChangesPerMethod =
+ new IdentityHashMap<>();
+
+ public void move(DexMethod from, boolean fromStatic, DexMethod to, boolean toStatic) {
+ move(from, fromStatic, to, toStatic, 0);
+ }
+
+ public void move(
+ DexMethod from,
+ boolean fromStatic,
+ DexMethod to,
+ boolean toStatic,
+ int numberOfExtraNullParameters) {
+ super.move(from, to);
+ int offsetDiff = 0;
+ int toOffset = BooleanUtils.intValue(!toStatic);
+ RewrittenPrototypeDescription.ArgumentInfoCollection.Builder builder =
+ RewrittenPrototypeDescription.ArgumentInfoCollection.builder();
+ if (fromStatic != toStatic) {
+ assert toStatic;
+ offsetDiff = 1;
+ builder.addArgumentInfo(
+ 0,
+ new RewrittenPrototypeDescription.RewrittenTypeInfo(
+ from.holder, to.proto.parameters.values[0]));
+ }
+ for (int i = 0; i < from.proto.parameters.size(); i++) {
+ DexType fromType = from.proto.parameters.values[i];
+ DexType toType = to.proto.parameters.values[i + offsetDiff];
+ if (fromType != toType) {
+ builder.addArgumentInfo(
+ i + offsetDiff + toOffset,
+ new RewrittenPrototypeDescription.RewrittenTypeInfo(fromType, toType));
+ }
+ }
+ RewrittenPrototypeDescription.RewrittenTypeInfo returnInfo =
+ from.proto.returnType == to.proto.returnType
+ ? null
+ : new RewrittenPrototypeDescription.RewrittenTypeInfo(
+ from.proto.returnType, to.proto.returnType);
+ prototypeChangesPerMethod.put(
+ to,
+ RewrittenPrototypeDescription.createForRewrittenTypes(returnInfo, builder.build())
+ .withExtraUnusedNullParameters(numberOfExtraNullParameters));
+ }
+
+ public EnumUnboxingLens build(
+ DexItemFactory dexItemFactory, GraphLens previousLens, Set<DexType> unboxedEnums) {
+ if (typeMap.isEmpty() && methodMap.isEmpty() && fieldMap.isEmpty()) {
+ return null;
+ }
+ return new EnumUnboxingLens(
+ typeMap,
+ methodMap,
+ fieldMap,
+ originalFieldSignatures,
+ originalMethodSignatures,
+ previousLens,
+ dexItemFactory,
+ ImmutableMap.copyOf(prototypeChangesPerMethod),
+ ImmutableSet.copyOf(unboxedEnums));
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
index 6c73aef..c67c231 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingRewriter.java
@@ -9,23 +9,23 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
-import com.android.tools.r8.graph.ClassAccessFlags;
import com.android.tools.r8.graph.DexAnnotationSet;
-import com.android.tools.r8.graph.DexApplication.Builder;
import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMember;
import com.android.tools.r8.graph.DexEncodedMethod;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexMember;
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.DexTypeList;
import com.android.tools.r8.graph.EnumValueInfoMapCollection;
import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfo;
import com.android.tools.r8.graph.EnumValueInfoMapCollection.EnumValueInfoMap;
import com.android.tools.r8.graph.FieldAccessFlags;
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.ir.analysis.type.ArrayTypeElement;
import com.android.tools.r8.ir.analysis.type.Nullability;
import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -46,11 +46,12 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldKnownData;
import com.android.tools.r8.ir.synthetic.EnumUnboxingCfCodeProvider;
-import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.collections.SortedProgramMethodSet;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Sets;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
@@ -63,7 +64,6 @@
public class EnumUnboxingRewriter {
- public static final String ENUM_UNBOXING_UTILITY_CLASS_NAME = "$r8$EnumUnboxingUtility";
public static final String ENUM_UNBOXING_UTILITY_METHOD_PREFIX = "$enumboxing$";
private static final int REQUIRED_CLASS_FILE_VERSION = 52;
@@ -71,8 +71,10 @@
private final DexItemFactory factory;
private final EnumValueInfoMapCollection enumsToUnbox;
private final EnumInstanceFieldDataMap unboxedEnumsInstanceFieldData;
+ private final UnboxedEnumMemberRelocator relocator;
+
private final Map<DexMethod, DexEncodedMethod> utilityMethods = new ConcurrentHashMap<>();
- private final Map<DexField, DexEncodedField> extraUtilityFields = new ConcurrentHashMap<>();
+ private final Map<DexField, DexEncodedField> utilityFields = new ConcurrentHashMap<>();
private final DexMethod ordinalUtilityMethod;
private final DexMethod equalsUtilityMethod;
@@ -84,7 +86,8 @@
EnumUnboxingRewriter(
AppView<AppInfoWithLiveness> appView,
Set<DexType> enumsToUnbox,
- EnumInstanceFieldDataMap unboxedEnumsInstanceFieldData) {
+ EnumInstanceFieldDataMap unboxedEnumsInstanceFieldData,
+ UnboxedEnumMemberRelocator relocator) {
this.appView = appView;
this.factory = appView.dexItemFactory();
EnumValueInfoMapCollection.Builder builder = EnumValueInfoMapCollection.builder();
@@ -94,38 +97,40 @@
}
this.enumsToUnbox = builder.build();
this.unboxedEnumsInstanceFieldData = unboxedEnumsInstanceFieldData;
+ this.relocator = relocator;
// Custom methods for java.lang.Enum methods ordinal, equals and compareTo.
+ DexType defaultEnumUnboxingUtility = relocator.getDefaultEnumUnboxingUtility();
this.ordinalUtilityMethod =
factory.createMethod(
- factory.enumUnboxingUtilityType,
+ defaultEnumUnboxingUtility,
factory.createProto(factory.intType, factory.intType),
ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "ordinal");
this.equalsUtilityMethod =
factory.createMethod(
- factory.enumUnboxingUtilityType,
+ defaultEnumUnboxingUtility,
factory.createProto(factory.booleanType, factory.intType, factory.intType),
ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "equals");
this.compareToUtilityMethod =
factory.createMethod(
- factory.enumUnboxingUtilityType,
+ defaultEnumUnboxingUtility,
factory.createProto(factory.intType, factory.intType, factory.intType),
ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "compareTo");
// Custom methods for generated field $VALUES initialization.
this.valuesUtilityMethod =
factory.createMethod(
- factory.enumUnboxingUtilityType,
+ defaultEnumUnboxingUtility,
factory.createProto(factory.intArrayType, factory.intType),
ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "values");
// Custom methods for Object#getClass without outValue and Objects.requireNonNull.
this.zeroCheckMethod =
factory.createMethod(
- factory.enumUnboxingUtilityType,
+ defaultEnumUnboxingUtility,
factory.createProto(factory.voidType, factory.intType),
ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "zeroCheck");
this.zeroCheckMessageMethod =
factory.createMethod(
- factory.enumUnboxingUtilityType,
+ defaultEnumUnboxingUtility,
factory.createProto(factory.voidType, factory.intType, factory.stringType),
ENUM_UNBOXING_UTILITY_METHOD_PREFIX + "zeroCheckMessage");
}
@@ -261,7 +266,7 @@
utilityMethods.computeIfAbsent(
valuesUtilityMethod, m -> synthesizeValuesUtilityMethod());
DexField fieldValues = createValuesField(holder);
- extraUtilityFields.computeIfAbsent(fieldValues, this::computeValuesEncodedField);
+ utilityFields.computeIfAbsent(fieldValues, this::computeValuesEncodedField);
DexMethod methodValues = createValuesMethod(holder);
utilityMethods.computeIfAbsent(
methodValues,
@@ -368,11 +373,11 @@
return type.toSourceString().replace('.', '$');
}
- private DexField createValuesField(DexType type) {
+ private DexField createValuesField(DexType enumType) {
return factory.createField(
- factory.enumUnboxingUtilityType,
+ relocator.getNewMemberLocationFor(enumType),
factory.intArrayType,
- factory.enumValuesFieldName + "$field$" + compatibleName(type));
+ factory.enumValuesFieldName + "$field$" + compatibleName(enumType));
}
private DexEncodedField computeValuesEncodedField(DexField field) {
@@ -384,22 +389,18 @@
null);
}
- private DexMethod createValuesMethod(DexType type) {
+ private DexMethod createValuesMethod(DexType enumType) {
return factory.createMethod(
- factory.enumUnboxingUtilityType,
+ relocator.getNewMemberLocationFor(enumType),
factory.createProto(factory.intArrayType),
- factory.enumValuesFieldName + "$method$" + compatibleName(type));
+ factory.enumValuesFieldName + "$method$" + compatibleName(enumType));
}
private DexEncodedMethod computeValuesEncodedMethod(
DexMethod method, DexField fieldValues, int numEnumInstances) {
CfCode cfCode =
new EnumUnboxingCfCodeProvider.EnumUnboxingValuesCfCodeProvider(
- appView,
- factory.enumUnboxingUtilityType,
- fieldValues,
- numEnumInstances,
- valuesUtilityMethod)
+ appView, method.holder, fieldValues, numEnumInstances, valuesUtilityMethod)
.generateCfCode();
return synthesizeUtilityMethod(cfCode, method, true);
}
@@ -415,7 +416,7 @@
+ compatibleName(enumType);
DexMethod fieldMethod =
factory.createMethod(
- factory.enumUnboxingUtilityType,
+ relocator.getNewMemberLocationFor(enumType),
factory.createProto(field.type, factory.intType),
methodName);
utilityMethods.computeIfAbsent(
@@ -429,7 +430,7 @@
String methodName = "string$valueOf$" + compatibleName(enumType);
DexMethod fieldMethod =
factory.createMethod(
- factory.enumUnboxingUtilityType,
+ relocator.getNewMemberLocationFor(enumType),
factory.createProto(factory.stringType, factory.intType),
methodName);
AbstractValue nullString =
@@ -440,14 +441,14 @@
return fieldMethod;
}
- private DexMethod computeValueOfUtilityMethod(DexType type) {
- assert enumsToUnbox.containsEnum(type);
+ private DexMethod computeValueOfUtilityMethod(DexType enumType) {
+ assert enumsToUnbox.containsEnum(enumType);
DexMethod valueOf =
factory.createMethod(
- factory.enumUnboxingUtilityType,
+ relocator.getNewMemberLocationFor(enumType),
factory.createProto(factory.intType, factory.stringType),
- "valueOf" + compatibleName(type));
- utilityMethods.computeIfAbsent(valueOf, m -> synthesizeValueOfUtilityMethod(m, type));
+ "valueOf" + compatibleName(enumType));
+ utilityMethods.computeIfAbsent(valueOf, m -> synthesizeValueOfUtilityMethod(m, enumType));
return valueOf;
}
@@ -468,50 +469,52 @@
return enumsToUnbox.containsEnum(classType) ? classType : null;
}
- void synthesizeEnumUnboxingUtilityMethods(
- Builder<?> builder, IRConverter converter, ExecutorService executorService)
+ void synthesizeEnumUnboxingUtilityMethods(IRConverter converter, ExecutorService executorService)
throws ExecutionException {
- // Synthesize a class which holds various utility methods that may be called from the IR
- // rewriting. If any of these methods are not used, they will be removed by the Enqueuer.
- List<DexEncodedMethod> requiredMethods = new ArrayList<>(utilityMethods.values());
- // Sort for deterministic order.
- requiredMethods.sort((m1, m2) -> m1.method.name.slowCompareTo(m2.method.name));
- if (requiredMethods.isEmpty()) {
+ // Append to the various utility classes, in deterministic order, the utility methods and
+ // fields required.
+ Map<DexType, List<DexEncodedMethod>> methodMap = triageEncodedMembers(utilityMethods.values());
+ if (methodMap.isEmpty()) {
+ assert utilityFields.isEmpty();
return;
}
- List<DexEncodedField> fields = new ArrayList<>(extraUtilityFields.values());
- fields.sort((f1, f2) -> f1.field.name.slowCompareTo(f2.field.name));
- DexProgramClass utilityClass =
- appView.definitionForProgramType(factory.enumUnboxingUtilityType);
- assert utilityClass != null : "Should have been synthesized upfront.";
- utilityClass.appendStaticFields(fields);
- utilityClass.addDirectMethods(requiredMethods);
- assert requiredMethods.stream().allMatch(DexEncodedMethod::isPublic);
- // TODO(b/147860220): Use processMethodsConcurrently on requiredMethods instead.
- converter.optimizeSynthesizedClass(utilityClass, executorService);
+ SortedProgramMethodSet wave = SortedProgramMethodSet.create();
+ methodMap.forEach(
+ (type, methodsSorted) -> {
+ DexProgramClass utilityClass = appView.definitionFor(type).asProgramClass();
+ assert utilityClass != null;
+ utilityClass.addDirectMethods(methodsSorted);
+ for (DexEncodedMethod dexEncodedMethod : methodsSorted) {
+ wave.add(new ProgramMethod(utilityClass, dexEncodedMethod));
+ }
+ });
+ Map<DexType, List<DexEncodedField>> fieldMap = triageEncodedMembers(utilityFields.values());
+ fieldMap.forEach(
+ (type, fieldsSorted) -> {
+ DexProgramClass utilityClass = appView.definitionFor(type).asProgramClass();
+ assert utilityClass != null;
+ utilityClass.appendStaticFields(fieldsSorted);
+ });
+ converter.processMethodsConcurrently(wave, executorService);
}
- public static DexProgramClass synthesizeEmptyEnumUnboxingUtilityClass(AppView<?> appView) {
- DexItemFactory factory = appView.dexItemFactory();
- return new DexProgramClass(
- factory.enumUnboxingUtilityType,
- null,
- new SynthesizedOrigin("EnumUnboxing ", EnumUnboxingRewriter.class),
- ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC),
- factory.objectType,
- DexTypeList.empty(),
- factory.createString("enumunboxing"),
- null,
- Collections.emptyList(),
- null,
- Collections.emptyList(),
- DexAnnotationSet.empty(),
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedField.EMPTY_ARRAY,
- DexEncodedMethod.EMPTY_ARRAY,
- DexEncodedMethod.EMPTY_ARRAY,
- factory.getSkipNameValidationForTesting(),
- DexProgramClass::checksumFromType);
+ <R extends DexMember<T, R>, T extends DexEncodedMember<T, R>>
+ Map<DexType, List<T>> triageEncodedMembers(Collection<T> encodedMembers) {
+ if (encodedMembers.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ Map<DexType, List<T>> encodedMembersMap = new IdentityHashMap<>();
+ // We compute encodedMembers by types.
+ for (T encodedMember : encodedMembers) {
+ List<T> members =
+ encodedMembersMap.computeIfAbsent(encodedMember.holder(), ignored -> new ArrayList<>());
+ members.add(encodedMember);
+ }
+ // We make the order deterministic.
+ for (List<T> value : encodedMembersMap.values()) {
+ value.sort((m1, m2) -> m1.toReference().slowCompareTo(m2.toReference()));
+ }
+ return encodedMembersMap;
}
private DexEncodedMethod synthesizeInstanceFieldMethod(
@@ -521,7 +524,7 @@
CfCode cfCode =
new EnumUnboxingCfCodeProvider.EnumUnboxingInstanceFieldCfCodeProvider(
appView,
- factory.enumUnboxingUtilityType,
+ method.holder,
field.type,
enumsToUnbox.getEnumValueInfoMap(enumType),
unboxedEnumsInstanceFieldData
@@ -540,7 +543,7 @@
CfCode cfCode =
new EnumUnboxingCfCodeProvider.EnumUnboxingValueOfCfCodeProvider(
appView,
- factory.enumUnboxingUtilityType,
+ method.holder,
enumType,
enumsToUnbox.getEnumValueInfoMap(enumType),
unboxedEnumsInstanceFieldData
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
new file mode 100644
index 0000000..879c909
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/EnumUnboxingTreeFixer.java
@@ -0,0 +1,221 @@
+// Copyright (c) 2020, 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.ir.optimize.enums;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexEncodedField;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexField;
+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.DexProto;
+import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.utils.OptionalBool;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+class EnumUnboxingTreeFixer {
+
+ private final Map<DexType, List<DexEncodedMethod>> unboxedEnumsMethods = new IdentityHashMap<>();
+ private final EnumUnboxingLens.Builder lensBuilder = EnumUnboxingLens.builder();
+ private final AppView<?> appView;
+ private final DexItemFactory factory;
+ private final Set<DexType> enumsToUnbox;
+ private final UnboxedEnumMemberRelocator relocator;
+ private final EnumUnboxingRewriter enumUnboxerRewriter;
+
+ EnumUnboxingTreeFixer(
+ AppView<?> appView,
+ Set<DexType> enumsToUnbox,
+ UnboxedEnumMemberRelocator relocator,
+ EnumUnboxingRewriter enumUnboxerRewriter) {
+ this.appView = appView;
+ this.factory = appView.dexItemFactory();
+ this.enumsToUnbox = enumsToUnbox;
+ this.relocator = relocator;
+ this.enumUnboxerRewriter = enumUnboxerRewriter;
+ }
+
+ GraphLens.NestedGraphLens fixupTypeReferences() {
+ assert enumUnboxerRewriter != null;
+ // Fix all methods and fields using enums to unbox.
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
+ if (enumsToUnbox.contains(clazz.type)) {
+ // Clear the initializers and move the static methods to the new location.
+ Set<DexEncodedMethod> methodsToRemove = Sets.newIdentityHashSet();
+ clazz
+ .methods()
+ .forEach(
+ m -> {
+ if (m.isInitializer()) {
+ clearEnumToUnboxMethod(m);
+ } else {
+ DexType newHolder = relocator.getNewMemberLocationFor(clazz.type);
+ List<DexEncodedMethod> movedMethods =
+ unboxedEnumsMethods.computeIfAbsent(newHolder, k -> new ArrayList<>());
+ movedMethods.add(fixupEncodedMethodToUtility(m, newHolder));
+ methodsToRemove.add(m);
+ }
+ });
+ clazz.getMethodCollection().removeMethods(methodsToRemove);
+ } else {
+ clazz.getMethodCollection().replaceMethods(this::fixupEncodedMethod);
+ fixupFields(clazz.staticFields(), clazz::setStaticField);
+ fixupFields(clazz.instanceFields(), clazz::setInstanceField);
+ }
+ }
+ for (DexType toUnbox : enumsToUnbox) {
+ lensBuilder.map(toUnbox, factory.intType);
+ }
+ unboxedEnumsMethods.forEach(
+ (newHolderType, movedMethods) -> {
+ DexProgramClass newHolderClass = appView.definitionFor(newHolderType).asProgramClass();
+ newHolderClass.addDirectMethods(movedMethods);
+ });
+ return lensBuilder.build(factory, appView.graphLens(), enumsToUnbox);
+ }
+
+ private void clearEnumToUnboxMethod(DexEncodedMethod enumMethod) {
+ // The compiler may have references to the enum methods, but such methods will be removed
+ // and they cannot be reprocessed since their rewriting through the lensCodeRewriter/
+ // enumUnboxerRewriter will generate invalid code.
+ // To work around this problem we clear such methods, i.e., we replace the code object by
+ // an empty throwing code object, so reprocessing won't take time and will be valid.
+ enumMethod.setCode(enumMethod.buildEmptyThrowingCode(appView.options()), appView);
+ }
+
+ private DexEncodedMethod fixupEncodedMethodToUtility(
+ DexEncodedMethod encodedMethod, DexType newHolder) {
+ DexMethod method = encodedMethod.method;
+ DexString newMethodName =
+ factory.createString(
+ enumUnboxerRewriter.compatibleName(method.holder)
+ + "$"
+ + (encodedMethod.isStatic() ? "s" : "v")
+ + "$"
+ + method.name.toString());
+ DexProto proto = encodedMethod.isStatic() ? method.proto : factory.prependHolderToProto(method);
+ DexMethod newMethod = factory.createMethod(newHolder, fixupProto(proto), newMethodName);
+ assert appView.definitionFor(encodedMethod.holder()).lookupMethod(newMethod) == null;
+ lensBuilder.move(method, encodedMethod.isStatic(), newMethod, true);
+ encodedMethod.accessFlags.promoteToPublic();
+ encodedMethod.accessFlags.promoteToStatic();
+ encodedMethod.clearAnnotations();
+ encodedMethod.clearParameterAnnotations();
+ return encodedMethod.toTypeSubstitutedMethod(newMethod);
+ }
+
+ private DexEncodedMethod fixupEncodedMethod(DexEncodedMethod encodedMethod) {
+ DexProto newProto = fixupProto(encodedMethod.proto());
+ if (newProto == encodedMethod.proto()) {
+ return encodedMethod;
+ }
+ assert !encodedMethod.isClassInitializer();
+ // We add the $enumunboxing$ suffix to make sure we do not create a library override.
+ String newMethodName =
+ encodedMethod.getName().toString()
+ + (encodedMethod.isNonPrivateVirtualMethod() ? "$enumunboxing$" : "");
+ DexMethod newMethod = factory.createMethod(encodedMethod.holder(), newProto, newMethodName);
+ newMethod = ensureUniqueMethod(encodedMethod, newMethod);
+ int numberOfExtraNullParameters = newMethod.getArity() - encodedMethod.method.getArity();
+ boolean isStatic = encodedMethod.isStatic();
+ lensBuilder.move(
+ encodedMethod.method, isStatic, newMethod, isStatic, numberOfExtraNullParameters);
+ DexEncodedMethod newEncodedMethod = encodedMethod.toTypeSubstitutedMethod(newMethod);
+ assert !encodedMethod.isLibraryMethodOverride().isTrue()
+ : "Enum unboxing is changing the signature of a library override in a non unboxed class.";
+ if (newEncodedMethod.isNonPrivateVirtualMethod()) {
+ newEncodedMethod.setLibraryMethodOverride(OptionalBool.FALSE);
+ }
+ return newEncodedMethod;
+ }
+
+ private DexMethod ensureUniqueMethod(DexEncodedMethod encodedMethod, DexMethod newMethod) {
+ DexClass holder = appView.definitionFor(encodedMethod.holder());
+ assert holder != null;
+ if (encodedMethod.isInstanceInitializer()) {
+ while (holder.lookupMethod(newMethod) != null) {
+ newMethod =
+ factory.createMethod(
+ newMethod.holder,
+ factory.appendTypeToProto(
+ newMethod.proto, relocator.getDefaultEnumUnboxingUtility()),
+ newMethod.name);
+ }
+ } else {
+ int index = 0;
+ while (holder.lookupMethod(newMethod) != null) {
+ newMethod =
+ factory.createMethod(
+ newMethod.holder,
+ newMethod.proto,
+ encodedMethod.getName().toString() + "$enumunboxing$" + index++);
+ }
+ }
+ return newMethod;
+ }
+
+ private void fixupFields(List<DexEncodedField> fields, DexClass.FieldSetter setter) {
+ if (fields == null) {
+ return;
+ }
+ for (int i = 0; i < fields.size(); i++) {
+ DexEncodedField encodedField = fields.get(i);
+ DexField field = encodedField.field;
+ DexType newType = fixupType(field.type);
+ if (newType != field.type) {
+ DexField newField = factory.createField(field.holder, newType, field.name);
+ lensBuilder.move(field, newField);
+ DexEncodedField newEncodedField = encodedField.toTypeSubstitutedField(newField);
+ setter.setField(i, newEncodedField);
+ if (encodedField.isStatic() && encodedField.hasExplicitStaticValue()) {
+ assert encodedField.getStaticValue() == DexValue.DexValueNull.NULL;
+ newEncodedField.setStaticValue(DexValue.DexValueInt.DEFAULT);
+ // TODO(b/150593449): Support conversion from DexValueEnum to DexValueInt.
+ }
+ }
+ }
+ }
+
+ private DexProto fixupProto(DexProto proto) {
+ DexType returnType = fixupType(proto.returnType);
+ DexType[] arguments = fixupTypes(proto.parameters.values);
+ return factory.createProto(returnType, arguments);
+ }
+
+ private DexType fixupType(DexType type) {
+ if (type.isArrayType()) {
+ DexType base = type.toBaseType(factory);
+ DexType fixed = fixupType(base);
+ if (base == fixed) {
+ return type;
+ }
+ return type.replaceBaseType(fixed, factory);
+ }
+ if (type.isClassType() && enumsToUnbox.contains(type)) {
+ DexType intType = factory.intType;
+ lensBuilder.map(type, intType);
+ return intType;
+ }
+ return type;
+ }
+
+ private DexType[] fixupTypes(DexType[] types) {
+ DexType[] result = new DexType[types.length];
+ for (int i = 0; i < result.length; i++) {
+ result[i] = fixupType(types[i]);
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/enums/UnboxedEnumMemberRelocator.java b/src/main/java/com/android/tools/r8/ir/optimize/enums/UnboxedEnumMemberRelocator.java
new file mode 100644
index 0000000..16c9118
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/enums/UnboxedEnumMemberRelocator.java
@@ -0,0 +1,151 @@
+// Copyright (c) 2020, 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.ir.optimize.enums;
+
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.ClassAccessFlags;
+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.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexTypeList;
+import com.android.tools.r8.graph.DirectMappedDexApplication;
+import com.android.tools.r8.graph.ProgramPackage;
+import com.android.tools.r8.graph.ProgramPackageCollection;
+import com.android.tools.r8.origin.SynthesizedOrigin;
+import com.google.common.collect.ImmutableMap;
+import java.util.Collections;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.Set;
+
+public class UnboxedEnumMemberRelocator {
+
+ public static final String ENUM_UNBOXING_UTILITY_CLASS_SUFFIX = "$r8$EnumUnboxingUtility";
+
+ // Default enum unboxing utility synthetic class used to hold all the shared unboxed enum
+ // methods (ordinal(I), equals(II), etc.) and the unboxed enums members which were free to be
+ // placed anywhere.
+ private final DexType defaultEnumUnboxingUtility;
+ // Some unboxed enum members have to be placed in a specific package, in this case, we keep a
+ // map from unboxed enum types to synthetic classes, so that all members of unboxed enums in the
+ // keys are moved to the corresponding value.
+ private final ImmutableMap<DexType, DexType> relocationMap;
+
+ public DexType getDefaultEnumUnboxingUtility() {
+ return defaultEnumUnboxingUtility;
+ }
+
+ public DexType getNewMemberLocationFor(DexType enumType) {
+ return relocationMap.getOrDefault(enumType, defaultEnumUnboxingUtility);
+ }
+
+ private UnboxedEnumMemberRelocator(
+ DexType defaultEnumUnboxingUtility, ImmutableMap<DexType, DexType> relocationMap) {
+ this.defaultEnumUnboxingUtility = defaultEnumUnboxingUtility;
+ this.relocationMap = relocationMap;
+ }
+
+ public static Builder builder(AppView<?> appView) {
+ return new Builder(appView);
+ }
+
+ public static class Builder {
+ private DexType defaultEnumUnboxingUtility;
+ private Map<DexType, DexType> relocationMap = new IdentityHashMap<>();
+ private final AppView<?> appView;
+
+ public Builder(AppView<?> appView) {
+ this.appView = appView;
+ }
+
+ public Builder synthesizeEnumUnboxingUtilityClasses(
+ Set<DexProgramClass> enumsToUnbox,
+ ProgramPackageCollection enumsToUnboxWithPackageRequirement,
+ DirectMappedDexApplication.Builder appBuilder) {
+ defaultEnumUnboxingUtility = synthesizeUtilityClass(enumsToUnbox, appBuilder);
+ if (!enumsToUnboxWithPackageRequirement.isEmpty()) {
+ synthesizeRelocationMap(enumsToUnboxWithPackageRequirement, appBuilder);
+ }
+ return this;
+ }
+
+ public UnboxedEnumMemberRelocator build() {
+ return new UnboxedEnumMemberRelocator(
+ defaultEnumUnboxingUtility, ImmutableMap.copyOf(relocationMap));
+ }
+
+ private void synthesizeRelocationMap(
+ ProgramPackageCollection enumsToUnboxWithPackageRequirement,
+ DirectMappedDexApplication.Builder appBuilder) {
+ for (ProgramPackage programPackage : enumsToUnboxWithPackageRequirement) {
+ Set<DexProgramClass> enumsToUnboxInPackage = programPackage.classesInPackage();
+ DexType utilityType = synthesizeUtilityClass(enumsToUnboxInPackage, appBuilder);
+ for (DexProgramClass enumToUnbox : enumsToUnboxInPackage) {
+ assert !relocationMap.containsKey(enumToUnbox.type);
+ relocationMap.put(enumToUnbox.type, utilityType);
+ }
+ }
+ }
+
+ private DexType synthesizeUtilityClass(
+ Set<DexProgramClass> contexts, DirectMappedDexApplication.Builder appBuilder) {
+ DexType deterministicContextType = findDeterministicContextType(contexts);
+ assert deterministicContextType.isClassType();
+ String descriptorString = deterministicContextType.toDescriptorString();
+ String descriptorPrefix = descriptorString.substring(0, descriptorString.length() - 1);
+ String syntheticClassDescriptor = descriptorPrefix + ENUM_UNBOXING_UTILITY_CLASS_SUFFIX + ";";
+ DexType type = appView.dexItemFactory().createType(syntheticClassDescriptor);
+ // The defaultEnumUnboxingUtility depends on all unboxable enums, and other synthetic types
+ // depend on a subset of the unboxable enums, the deterministicContextType can therefore
+ // be found twice, and in that case the same utility class can be used for both.
+ if (type == defaultEnumUnboxingUtility) {
+ return defaultEnumUnboxingUtility;
+ }
+ assert appView.appInfo().definitionForWithoutExistenceAssert(type) == null;
+ DexProgramClass syntheticClass =
+ new DexProgramClass(
+ type,
+ null,
+ new SynthesizedOrigin("enum unboxing", EnumUnboxer.class),
+ ClassAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC),
+ appView.dexItemFactory().objectType,
+ DexTypeList.empty(),
+ null,
+ null,
+ Collections.emptyList(),
+ null,
+ Collections.emptyList(),
+ DexAnnotationSet.empty(),
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedField.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY,
+ DexEncodedMethod.EMPTY_ARRAY,
+ appView.dexItemFactory().getSkipNameValidationForTesting(),
+ DexProgramClass::checksumFromType);
+ appBuilder.addSynthesizedClass(syntheticClass);
+ appView
+ .appInfo()
+ .addSynthesizedClass(
+ syntheticClass, appView.appInfo().getMainDexClasses().containsAnyOf(contexts));
+ return syntheticClass.type;
+ }
+
+ private DexType findDeterministicContextType(Set<DexProgramClass> contexts) {
+ DexType deterministicContext = null;
+ for (DexProgramClass context : contexts) {
+ if (deterministicContext == null) {
+ deterministicContext = context.type;
+ } else if (context.type.slowCompareTo(deterministicContext) < 0) {
+ deterministicContext = context.type;
+ }
+ }
+ return deterministicContext;
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
index a7b1576..3414861 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaMerger.java
@@ -254,8 +254,7 @@
cls.getKotlinInfo().isSyntheticClass()
&& cls.getKotlinInfo().asSyntheticClass().isLambda()
&& KotlinLambdaGroupIdFactory.hasValidAnnotations(kotlin, cls)
- && (appView.options().featureSplitConfiguration == null
- || !appView.options().featureSplitConfiguration.isInFeature(cls)))
+ && !appView.appInfo().getClassToFeatureSplitMap().isInFeature(cls))
.sorted((a, b) -> a.type.slowCompareTo(b.type)) // Ensure stable ordering.
.forEachOrdered(
lambda -> {
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
index 0372a33..0231d43 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/ClassStaticizer.java
@@ -15,7 +15,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.DexProto;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult;
@@ -38,7 +37,6 @@
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import java.util.ArrayList;
-import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.ListIterator;
@@ -132,23 +130,28 @@
DexType type = field.field.type;
if (singletonFields.put(type, field) != null) {
// There is already candidate singleton field found.
- notEligible.add(type);
+ markNotEligible(type, notEligible);
}
}
// Don't allow fields with this candidate types.
for (DexEncodedField field : cls.instanceFields()) {
- notEligible.add(field.field.type);
+ markNotEligible(field.field.type, notEligible);
}
// Don't allow methods that take a value of this type.
for (DexEncodedMethod method : cls.methods()) {
- DexProto proto = method.method.proto;
- notEligible.addAll(Arrays.asList(proto.parameters.values));
+ for (DexType parameter : method.getProto().parameters.values) {
+ markNotEligible(parameter, notEligible);
+ }
+ if (method.isSynchronized()) {
+ markNotEligible(cls.type, notEligible);
+ }
}
// High-level limitations on what classes we consider eligible.
- if (cls.isInterface() // Must not be an interface or an abstract class.
+ if (cls.isInterface()
+ // Must not be an interface or an abstract class.
|| cls.accessFlags.isAbstract()
// Don't support candidates with instance fields
|| cls.instanceFields().size() > 0
@@ -159,7 +162,7 @@
// Staticizing classes implementing interfaces is more
// difficult, so don't support it until we really need it.
|| !cls.interfaces.isEmpty()) {
- notEligible.add(cls.type);
+ markNotEligible(cls.type, notEligible);
}
});
@@ -180,6 +183,12 @@
});
}
+ private void markNotEligible(DexType type, Set<DexType> notEligible) {
+ if (type.isClassType()) {
+ notEligible.add(type);
+ }
+ }
+
private boolean isPinned(DexClass clazz, DexEncodedField singletonField) {
AppInfoWithLiveness appInfo = appView.appInfo();
if (appInfo.isPinned(clazz.type) || appInfo.isPinned(singletonField.field)) {
diff --git a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
index 477f516..012bd0e 100644
--- a/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
+++ b/src/main/java/com/android/tools/r8/ir/regalloc/LinearScanRegisterAllocator.java
@@ -2262,8 +2262,9 @@
}
LiveIntervalsUse firstUseWithLowerLimit = null;
boolean hasUsesBeforeFirstUseWithLowerLimit = false;
+ int highestRegisterNumber = registerNumber + spilled.requiredRegisters() - 1;
for (LiveIntervalsUse use : spilled.getUses()) {
- if (registerNumber > use.getLimit()) {
+ if (highestRegisterNumber > use.getLimit()) {
firstUseWithLowerLimit = use;
break;
} else {
diff --git a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
index ec34d75..e13331f 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -42,6 +42,7 @@
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.naming.ProguardMapSupplier;
import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.ImmutableMap;
@@ -113,6 +114,7 @@
marker.isRelocator() ? Optional.empty() : Optional.of(marker.toString());
LensCodeRewriterUtils rewriter = new LensCodeRewriterUtils(appView);
for (DexProgramClass clazz : application.classes()) {
+ assert SyntheticItems.verifyNotInternalSynthetic(clazz.getType());
if (clazz.getSynthesizedFrom().isEmpty()
|| options.isDesugaredLibraryCompilation()
|| options.cfToCfDesugar) {
diff --git a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
index 5163a17..848008c 100644
--- a/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
+++ b/src/main/java/com/android/tools/r8/repackaging/Repackaging.java
@@ -63,7 +63,7 @@
// For each package, find the set of classes that can be repackaged, and move them to the
// desired namespace.
Map<DexType, DexType> mappings = new IdentityHashMap<>();
- for (ProgramPackage pkg : ProgramPackageCollection.create(appView)) {
+ for (ProgramPackage pkg : ProgramPackageCollection.createWithAllProgramClasses(appView)) {
Iterable<DexProgramClass> classesToRepackage =
computeClassesToRepackage(pkg, executorService);
String newPackageDescriptor = getNewPackageDescriptor(pkg);
diff --git a/src/main/java/com/android/tools/r8/retrace/Retrace.java b/src/main/java/com/android/tools/r8/retrace/Retrace.java
index 8e65f12..f34a5aa 100644
--- a/src/main/java/com/android/tools/r8/retrace/Retrace.java
+++ b/src/main/java/com/android/tools/r8/retrace/Retrace.java
@@ -49,7 +49,7 @@
public static final String USAGE_MESSAGE =
StringUtils.lines(
- "Usage: retrace <proguard-map> <stacktrace-file> [--regex <regexp>, --verbose, --info]",
+ "Usage: retrace <proguard-map> [stack-trace-file] [--regex <regexp>, --verbose, --info]",
" where <proguard-map> is an r8 generated mapping file.");
private static Builder parseArguments(String[] args, DiagnosticsHandler diagnosticsHandler) {
diff --git a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
index 6c6bab5..627d84f 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -7,6 +7,7 @@
import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
import static com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult.isOverriding;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClass;
@@ -40,14 +41,13 @@
import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
import com.android.tools.r8.graph.SubtypingInfo;
-import com.android.tools.r8.graph.SyntheticItems;
-import com.android.tools.r8.graph.SyntheticItems.CommittedItems;
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
import com.android.tools.r8.ir.desugar.InterfaceMethodRewriter;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
import com.android.tools.r8.ir.desugar.TwrCloseResourceRewriter;
+import com.android.tools.r8.synthesis.CommittedItems;
import com.android.tools.r8.utils.CollectionUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
@@ -163,8 +163,11 @@
public final PredicateSet<DexType> alwaysClassInline;
/** All types that *must* never be inlined due to a configuration directive (testing only). */
public final Set<DexType> neverClassInline;
- /** All types that *must* never be merged due to a configuration directive (testing only). */
- public final Set<DexType> neverMerge;
+
+ private final Set<DexType> noVerticalClassMerging;
+ private final Set<DexType> noHorizontalClassMerging;
+ private final Set<DexType> noStaticClassMerging;
+
/** Set of const-class references. */
public final Set<DexType> constClassReferences;
/**
@@ -195,9 +198,9 @@
// TODO(zerny): Clean up the constructors so we have just one.
AppInfoWithLiveness(
- DirectMappedDexApplication application,
+ CommittedItems syntheticItems,
+ ClassToFeatureSplitMap classToFeatureSplitMap,
MainDexClasses mainDexClasses,
- SyntheticItems.CommittedItems syntheticItems,
Set<DexType> deadProtoTypes,
Set<DexType> missingTypes,
Set<DexType> liveTypes,
@@ -230,7 +233,9 @@
Set<DexMethod> neverReprocess,
PredicateSet<DexType> alwaysClassInline,
Set<DexType> neverClassInline,
- Set<DexType> neverMerge,
+ Set<DexType> noVerticalClassMerging,
+ Set<DexType> noHorizontalClassMerging,
+ Set<DexType> noStaticClassMerging,
Set<DexReference> neverPropagateValue,
Object2BooleanMap<DexReference> identifierNameStrings,
Set<DexType> prunedTypes,
@@ -238,7 +243,7 @@
EnumValueInfoMapCollection enumValueInfoMaps,
Set<DexType> constClassReferences,
Map<DexType, Visibility> initClassReferences) {
- super(application, mainDexClasses, syntheticItems);
+ super(syntheticItems, classToFeatureSplitMap, mainDexClasses);
this.deadProtoTypes = deadProtoTypes;
this.missingTypes = missingTypes;
this.liveTypes = liveTypes;
@@ -271,7 +276,9 @@
this.neverReprocess = neverReprocess;
this.alwaysClassInline = alwaysClassInline;
this.neverClassInline = neverClassInline;
- this.neverMerge = neverMerge;
+ this.noVerticalClassMerging = noVerticalClassMerging;
+ this.noHorizontalClassMerging = noHorizontalClassMerging;
+ this.noStaticClassMerging = noStaticClassMerging;
this.neverPropagateValue = neverPropagateValue;
this.identifierNameStrings = identifierNameStrings;
this.prunedTypes = prunedTypes;
@@ -315,7 +322,9 @@
Set<DexMethod> neverReprocess,
PredicateSet<DexType> alwaysClassInline,
Set<DexType> neverClassInline,
- Set<DexType> neverMerge,
+ Set<DexType> noVerticalClassMerging,
+ Set<DexType> noHorizontalClassMerging,
+ Set<DexType> noStaticClassMerging,
Set<DexReference> neverPropagateValue,
Object2BooleanMap<DexReference> identifierNameStrings,
Set<DexType> prunedTypes,
@@ -324,9 +333,9 @@
Set<DexType> constClassReferences,
Map<DexType, Visibility> initClassReferences) {
super(
- appInfoWithClassHierarchy.app(),
- appInfoWithClassHierarchy.getMainDexClasses(),
- appInfoWithClassHierarchy.getSyntheticItems().commit(appInfoWithClassHierarchy.app()));
+ appInfoWithClassHierarchy.getSyntheticItems().commit(appInfoWithClassHierarchy.app()),
+ appInfoWithClassHierarchy.getClassToFeatureSplitMap(),
+ appInfoWithClassHierarchy.getMainDexClasses());
this.deadProtoTypes = deadProtoTypes;
this.missingTypes = missingTypes;
this.liveTypes = liveTypes;
@@ -359,7 +368,9 @@
this.neverReprocess = neverReprocess;
this.alwaysClassInline = alwaysClassInline;
this.neverClassInline = neverClassInline;
- this.neverMerge = neverMerge;
+ this.noVerticalClassMerging = noVerticalClassMerging;
+ this.noHorizontalClassMerging = noHorizontalClassMerging;
+ this.noStaticClassMerging = noStaticClassMerging;
this.neverPropagateValue = neverPropagateValue;
this.identifierNameStrings = identifierNameStrings;
this.prunedTypes = prunedTypes;
@@ -369,12 +380,16 @@
this.initClassReferences = initClassReferences;
}
- private AppInfoWithLiveness(AppInfoWithLiveness previous) {
+ private AppInfoWithLiveness(
+ AppInfoWithLiveness previous, CommittedItems committedItems, Set<DexType> removedTypes) {
this(
- previous,
+ committedItems,
+ previous.getClassToFeatureSplitMap(),
+ previous.getMainDexClasses(),
previous.deadProtoTypes,
previous.missingTypes,
- previous.liveTypes,
+ CollectionUtils.mergeSets(
+ Sets.difference(previous.liveTypes, removedTypes), committedItems.getCommittedTypes()),
previous.instantiatedAppServices,
previous.targetedMethods,
previous.failedResolutionTargets,
@@ -404,7 +419,9 @@
previous.neverReprocess,
previous.alwaysClassInline,
previous.neverClassInline,
- previous.neverMerge,
+ previous.noVerticalClassMerging,
+ previous.noHorizontalClassMerging,
+ previous.noStaticClassMerging,
previous.neverPropagateValue,
previous.identifierNameStrings,
previous.prunedTypes,
@@ -417,15 +434,17 @@
private AppInfoWithLiveness(
AppInfoWithLiveness previous,
DirectMappedDexApplication application,
- Collection<DexType> removedClasses,
+ Set<DexType> removedClasses,
Collection<DexReference> additionalPinnedItems) {
this(
- application,
- previous.getMainDexClasses(),
- previous.getSyntheticItems().commit(application),
+ previous.getSyntheticItems().commitPrunedClasses(application, removedClasses),
+ previous.getClassToFeatureSplitMap().withoutPrunedClasses(removedClasses),
+ previous.getMainDexClasses().withoutPrunedClasses(removedClasses),
previous.deadProtoTypes,
previous.missingTypes,
- previous.liveTypes,
+ removedClasses == null
+ ? previous.liveTypes
+ : Sets.difference(previous.liveTypes, removedClasses),
previous.instantiatedAppServices,
previous.targetedMethods,
previous.failedResolutionTargets,
@@ -455,7 +474,9 @@
previous.neverReprocess,
previous.alwaysClassInline,
previous.neverClassInline,
- previous.neverMerge,
+ previous.noVerticalClassMerging,
+ previous.noHorizontalClassMerging,
+ previous.noStaticClassMerging,
previous.neverPropagateValue,
previous.identifierNameStrings,
removedClasses == null
@@ -510,9 +531,9 @@
Map<DexField, Int2ReferenceMap<DexField>> switchMaps,
EnumValueInfoMapCollection enumValueInfoMaps) {
super(
- previous.app(),
- previous.getMainDexClasses(),
- previous.getSyntheticItems().commit(previous.app()));
+ previous.getSyntheticItems().commit(previous.app()),
+ previous.getClassToFeatureSplitMap(),
+ previous.getMainDexClasses());
this.deadProtoTypes = previous.deadProtoTypes;
this.missingTypes = previous.missingTypes;
this.liveTypes = previous.liveTypes;
@@ -545,7 +566,9 @@
this.neverReprocess = previous.neverReprocess;
this.alwaysClassInline = previous.alwaysClassInline;
this.neverClassInline = previous.neverClassInline;
- this.neverMerge = previous.neverMerge;
+ this.noVerticalClassMerging = previous.noVerticalClassMerging;
+ this.noHorizontalClassMerging = previous.noHorizontalClassMerging;
+ this.noStaticClassMerging = previous.noStaticClassMerging;
this.neverPropagateValue = previous.neverPropagateValue;
this.identifierNameStrings = previous.identifierNameStrings;
this.prunedTypes = previous.prunedTypes;
@@ -570,8 +593,6 @@
|| InterfaceMethodRewriter.isCompanionClassType(type)
|| InterfaceMethodRewriter.hasDispatchClassSuffix(type)
|| InterfaceMethodRewriter.isEmulatedLibraryClassType(type)
- || type.toDescriptorString().startsWith("L$r8$backportedMethods$")
- || type.toDescriptorString().startsWith("Lj$/$r8$backportedMethods$")
|| type.toDescriptorString().startsWith("Lj$/$r8$retargetLibraryMember$")
|| TwrCloseResourceRewriter.isUtilityClassDescriptor(type)
// TODO(b/150736225): Not sure how to remove these.
@@ -956,7 +977,7 @@
*/
public AppInfoWithLiveness prunedCopyFrom(
DirectMappedDexApplication application,
- Collection<DexType> removedClasses,
+ Set<DexType> removedClasses,
Collection<DexReference> additionalPinnedItems) {
assert checkIfObsolete();
if (!removedClasses.isEmpty()) {
@@ -966,6 +987,11 @@
return new AppInfoWithLiveness(this, application, removedClasses, additionalPinnedItems);
}
+ public AppInfoWithLiveness rebuildWithLiveness(
+ CommittedItems committedItems, Set<DexType> removedTypes) {
+ return new AppInfoWithLiveness(this, committedItems, removedTypes);
+ }
+
public AppInfoWithLiveness rewrittenWithLens(
DirectMappedDexApplication application, NestedGraphLens lens) {
assert checkIfObsolete();
@@ -986,12 +1012,12 @@
.map(FieldResolutionResult::getResolvedField)
.collect(Collectors.toList()));
- CommittedItems committedItems = getSyntheticItems().commit(application, lens);
+ CommittedItems committedItems = getSyntheticItems().commitRewrittenWithLens(application, lens);
DexDefinitionSupplier definitionSupplier = application.getDefinitionsSupplier(committedItems);
return new AppInfoWithLiveness(
- application,
- getMainDexClasses().rewrittenWithLens(lens),
committedItems,
+ getClassToFeatureSplitMap().rewrittenWithLens(lens),
+ getMainDexClasses().rewrittenWithLens(lens),
deadProtoTypes,
missingTypes,
lens.rewriteTypes(liveTypes),
@@ -1028,7 +1054,9 @@
lens.rewriteMethods(neverReprocess),
alwaysClassInline.rewriteItems(lens::lookupType),
lens.rewriteTypes(neverClassInline),
- lens.rewriteTypes(neverMerge),
+ lens.rewriteTypes(noVerticalClassMerging),
+ lens.rewriteTypes(noHorizontalClassMerging),
+ lens.rewriteTypes(noStaticClassMerging),
lens.rewriteReferences(neverPropagateValue),
lens.rewriteReferenceKeys(identifierNameStrings),
// Don't rewrite pruned types - the removed types are identified by their original name.
@@ -1402,4 +1430,28 @@
this)
.shouldBreak();
}
+
+ /**
+ * All types that *must* never be merged vertically due to a configuration directive (testing
+ * only).
+ */
+ public Set<DexType> getNoVerticalClassMergingSet() {
+ return noVerticalClassMerging;
+ }
+
+ /**
+ * All types that *must* never be merged horizontally due to a configuration directive (testing
+ * only).
+ */
+ public Set<DexType> getNoHorizontalClassMergingSet() {
+ return noHorizontalClassMerging;
+ }
+
+ /**
+ * All types that *must* never be merged by the static class merger due to a configuration
+ * directive (testing only).
+ */
+ public Set<DexType> getNoStaticClassMergingSet() {
+ return noStaticClassMerging;
+ }
}
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 d692cef..98def17 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2743,7 +2743,7 @@
}
public NestedGraphLens buildGraphLens(AppView<?> appView) {
- return lambdaRewriter != null ? lambdaRewriter.buildMappingLens(appView) : null;
+ return lambdaRewriter != null ? lambdaRewriter.fixup() : null;
}
private void keepClassWithRules(DexProgramClass clazz, Set<ProguardKeepRuleBase> rules) {
@@ -2885,7 +2885,7 @@
// Now all additions are computed, the application is atomically extended with those additions.
appInfo =
- appInfo.rebuild(
+ appInfo.rebuildWithClassHierarchy(
app -> {
Builder appBuilder = app.asDirect().builder();
additions.amendApplication(appBuilder);
@@ -3019,9 +3019,9 @@
AppInfoWithLiveness appInfoWithLiveness =
new AppInfoWithLiveness(
- app,
- appInfo.getMainDexClasses(),
appInfo.getSyntheticItems().commit(app),
+ appInfo.getClassToFeatureSplitMap(),
+ appInfo.getMainDexClasses(),
deadProtoTypes,
mode.isFinalTreeShaking()
? Sets.union(initialMissingTypes, missingTypes)
@@ -3059,7 +3059,9 @@
rootSet.neverReprocess,
rootSet.alwaysClassInline,
rootSet.neverClassInline,
- rootSet.neverMerge,
+ rootSet.noVerticalClassMerging,
+ rootSet.noHorizontalClassMerging,
+ rootSet.noStaticClassMerging,
rootSet.neverPropagateValue,
joinIdentifierNameStrings(rootSet.identifierNameStrings, identifierNameStrings),
Collections.emptySet(),
diff --git a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
index 8841f15..18709f3 100644
--- a/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
+++ b/src/main/java/com/android/tools/r8/shaking/IfRuleEvaluator.java
@@ -300,6 +300,13 @@
if (neverInlineRuleForCondition != null) {
rootSetBuilder.runPerRule(executorService, futures, neverInlineRuleForCondition, null);
}
+
+ // Prevent horizontal class merging of any -if rule members.
+ NoHorizontalClassMergingRule noHorizontalClassMergingRule =
+ materializedRule.noHorizontalClassMergingRuleForCondition(dexItemFactory);
+ if (noHorizontalClassMergingRule != null) {
+ rootSetBuilder.runPerRule(executorService, futures, noHorizontalClassMergingRule, null);
+ }
}
// Keep whatever is required by the -if rule.
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java b/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java
index cfadae32..67cd3b8 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java
@@ -83,6 +83,16 @@
return mainDexClasses.size();
}
+ public MainDexClasses withoutPrunedClasses(Set<DexType> prunedClasses) {
+ MainDexClasses mainDexClassesAfterPruning = createEmptyMainDexClasses();
+ for (DexType mainDexClass : mainDexClasses) {
+ if (!prunedClasses.contains(mainDexClass)) {
+ mainDexClassesAfterPruning.mainDexClasses.add(mainDexClass);
+ }
+ }
+ return mainDexClassesAfterPruning;
+ }
+
public static class Builder {
private final Set<DexType> mainDexClasses = Sets.newIdentityHashSet();
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java b/src/main/java/com/android/tools/r8/shaking/NoHorizontalClassMergingRule.java
similarity index 65%
copy from src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java
copy to src/main/java/com/android/tools/r8/shaking/NoHorizontalClassMergingRule.java
index ee57043..acaedac 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/NoHorizontalClassMergingRule.java
@@ -1,40 +1,32 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2020, 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.shaking;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
import java.util.List;
-public class ClassMergingRule extends ProguardConfigurationRule {
+public class NoHorizontalClassMergingRule extends ProguardConfigurationRule {
- public enum Type {
- NEVER
- }
+ public static final String RULE_NAME = "nohorizontalclassmerging";
- public static class Builder extends ProguardConfigurationRule.Builder<ClassMergingRule, Builder> {
+ public static class Builder
+ extends ProguardConfigurationRule.Builder<NoHorizontalClassMergingRule, Builder> {
private Builder() {
super();
}
- Type type;
-
@Override
- public Builder self() {
- return this;
- }
-
- public Builder setType(Type type) {
- this.type = type;
+ public NoHorizontalClassMergingRule.Builder self() {
return this;
}
@Override
- public ClassMergingRule build() {
- return new ClassMergingRule(
+ public NoHorizontalClassMergingRule build() {
+ return new NoHorizontalClassMergingRule(
origin,
getPosition(),
source,
@@ -47,14 +39,11 @@
buildInheritanceAnnotations(),
inheritanceClassName,
inheritanceIsExtends,
- memberRules,
- type);
+ memberRules);
}
}
- private final Type type;
-
- private ClassMergingRule(
+ private NoHorizontalClassMergingRule(
Origin origin,
Position position,
String source,
@@ -67,8 +56,7 @@
List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- List<ProguardMemberRule> memberRules,
- Type type) {
+ List<ProguardMemberRule> memberRules) {
super(
origin,
position,
@@ -83,23 +71,14 @@
inheritanceClassName,
inheritanceIsExtends,
memberRules);
- this.type = type;
}
public static Builder builder() {
return new Builder();
}
- public Type getType() {
- return type;
- }
-
@Override
String typeString() {
- switch (type) {
- case NEVER:
- return "nevermerge";
- }
- throw new Unreachable("Unknown class merging type " + type);
+ return RULE_NAME;
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java b/src/main/java/com/android/tools/r8/shaking/NoStaticClassMergingRule.java
similarity index 65%
copy from src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java
copy to src/main/java/com/android/tools/r8/shaking/NoStaticClassMergingRule.java
index ee57043..dc19834 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/NoStaticClassMergingRule.java
@@ -1,40 +1,31 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2020, 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.shaking;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
import java.util.List;
-public class ClassMergingRule extends ProguardConfigurationRule {
+public class NoStaticClassMergingRule extends ProguardConfigurationRule {
+ public static final String RULE_NAME = "nostaticclassmerging";
- public enum Type {
- NEVER
- }
-
- public static class Builder extends ProguardConfigurationRule.Builder<ClassMergingRule, Builder> {
+ public static class Builder
+ extends ProguardConfigurationRule.Builder<NoStaticClassMergingRule, Builder> {
private Builder() {
super();
}
- Type type;
-
@Override
- public Builder self() {
- return this;
- }
-
- public Builder setType(Type type) {
- this.type = type;
+ public NoStaticClassMergingRule.Builder self() {
return this;
}
@Override
- public ClassMergingRule build() {
- return new ClassMergingRule(
+ public NoStaticClassMergingRule build() {
+ return new NoStaticClassMergingRule(
origin,
getPosition(),
source,
@@ -47,14 +38,11 @@
buildInheritanceAnnotations(),
inheritanceClassName,
inheritanceIsExtends,
- memberRules,
- type);
+ memberRules);
}
}
- private final Type type;
-
- private ClassMergingRule(
+ private NoStaticClassMergingRule(
Origin origin,
Position position,
String source,
@@ -67,8 +55,7 @@
List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- List<ProguardMemberRule> memberRules,
- Type type) {
+ List<ProguardMemberRule> memberRules) {
super(
origin,
position,
@@ -83,23 +70,14 @@
inheritanceClassName,
inheritanceIsExtends,
memberRules);
- this.type = type;
}
public static Builder builder() {
return new Builder();
}
- public Type getType() {
- return type;
- }
-
@Override
String typeString() {
- switch (type) {
- case NEVER:
- return "nevermerge";
- }
- throw new Unreachable("Unknown class merging type " + type);
+ return RULE_NAME;
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java b/src/main/java/com/android/tools/r8/shaking/NoVerticalClassMergingRule.java
similarity index 68%
rename from src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java
rename to src/main/java/com/android/tools/r8/shaking/NoVerticalClassMergingRule.java
index ee57043..edda33c 100644
--- a/src/main/java/com/android/tools/r8/shaking/ClassMergingRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/NoVerticalClassMergingRule.java
@@ -3,38 +3,29 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.shaking;
-import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.position.Position;
import java.util.List;
-public class ClassMergingRule extends ProguardConfigurationRule {
+public class NoVerticalClassMergingRule extends ProguardConfigurationRule {
- public enum Type {
- NEVER
- }
+ public static final String RULE_NAME = "noverticalclassmerging";
- public static class Builder extends ProguardConfigurationRule.Builder<ClassMergingRule, Builder> {
+ public static class Builder
+ extends ProguardConfigurationRule.Builder<NoVerticalClassMergingRule, Builder> {
private Builder() {
super();
}
- Type type;
-
@Override
public Builder self() {
return this;
}
- public Builder setType(Type type) {
- this.type = type;
- return this;
- }
-
@Override
- public ClassMergingRule build() {
- return new ClassMergingRule(
+ public NoVerticalClassMergingRule build() {
+ return new NoVerticalClassMergingRule(
origin,
getPosition(),
source,
@@ -47,14 +38,11 @@
buildInheritanceAnnotations(),
inheritanceClassName,
inheritanceIsExtends,
- memberRules,
- type);
+ memberRules);
}
}
- private final Type type;
-
- private ClassMergingRule(
+ private NoVerticalClassMergingRule(
Origin origin,
Position position,
String source,
@@ -67,8 +55,7 @@
List<ProguardTypeMatcher> inheritanceAnnotations,
ProguardTypeMatcher inheritanceClassName,
boolean inheritanceIsExtends,
- List<ProguardMemberRule> memberRules,
- Type type) {
+ List<ProguardMemberRule> memberRules) {
super(
origin,
position,
@@ -83,23 +70,14 @@
inheritanceClassName,
inheritanceIsExtends,
memberRules);
- this.type = type;
}
public static Builder builder() {
return new Builder();
}
- public Type getType() {
- return type;
- }
-
@Override
String typeString() {
- switch (type) {
- case NEVER:
- return "nevermerge";
- }
- throw new Unreachable("Unknown class merging type " + type);
+ return RULE_NAME;
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
index 2bf270a..9269a2a 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardClassSpecification.java
@@ -92,8 +92,9 @@
return inheritanceIsExtends;
}
- public void setInheritanceIsExtends(boolean inheritanceIsExtends) {
+ public B setInheritanceIsExtends(boolean inheritanceIsExtends) {
this.inheritanceIsExtends = inheritanceIsExtends;
+ return self();
}
public boolean hasInheritanceClassName() {
@@ -104,13 +105,15 @@
return inheritanceClassName;
}
- public void setInheritanceClassName(ProguardTypeMatcher inheritanceClassName) {
+ public B setInheritanceClassName(ProguardTypeMatcher inheritanceClassName) {
this.inheritanceClassName = inheritanceClassName;
+ return self();
}
- public void addInheritanceAnnotations(List<ProguardTypeMatcher> inheritanceAnnotations) {
+ public B addInheritanceAnnotations(List<ProguardTypeMatcher> inheritanceAnnotations) {
assert inheritanceAnnotations != null;
this.inheritanceAnnotations.addAll(inheritanceAnnotations);
+ return self();
}
public List<ProguardTypeMatcher> buildInheritanceAnnotations() {
@@ -139,33 +142,38 @@
return classTypeNegated;
}
- public void setClassTypeNegated(boolean classTypeNegated) {
+ public B setClassTypeNegated(boolean classTypeNegated) {
this.classTypeNegated = classTypeNegated;
+ return self();
}
public ProguardAccessFlags getClassAccessFlags() {
return classAccessFlags;
}
- public void setClassAccessFlags(ProguardAccessFlags flags) {
+ public B setClassAccessFlags(ProguardAccessFlags flags) {
classAccessFlags = flags;
+ return self();
}
public ProguardAccessFlags getNegatedClassAccessFlags() {
return negatedClassAccessFlags;
}
- public void setNegatedClassAccessFlags(ProguardAccessFlags flags) {
+ public B setNegatedClassAccessFlags(ProguardAccessFlags flags) {
negatedClassAccessFlags = flags;
+ return self();
}
- public void addClassAnnotation(ProguardTypeMatcher classAnnotation) {
+ public B addClassAnnotation(ProguardTypeMatcher classAnnotation) {
classAnnotations.add(classAnnotation);
+ return self();
}
- public void addClassAnnotations(List<ProguardTypeMatcher> classAnnotations) {
+ public B addClassAnnotations(List<ProguardTypeMatcher> classAnnotations) {
assert classAnnotations != null;
this.classAnnotations.addAll(classAnnotations);
+ return self();
}
public List<ProguardTypeMatcher> buildClassAnnotations() {
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
index 6b5604e..d846f49 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -302,9 +302,9 @@
parseClassFilter(configurationBuilder::addDontWarnPattern);
} else if (acceptString("dontnote")) {
parseClassFilter(configurationBuilder::addDontNotePattern);
- } else if (acceptString("repackageclasses")) {
+ } else if (acceptString(REPACKAGE_CLASSES)) {
if (configurationBuilder.getPackageObfuscationMode() == PackageObfuscationMode.FLATTEN) {
- warnOverridingOptions("repackageclasses", "flattenpackagehierarchy", optionStart);
+ warnOverridingOptions(REPACKAGE_CLASSES, FLATTEN_PACKAGE_HIERARCHY, optionStart);
}
skipWhitespace();
char quote = acceptQuoteIfPresent();
@@ -318,9 +318,9 @@
configurationBuilder.setPackagePrefix(parsePackageNameOrEmptyString());
}
}
- } else if (acceptString("flattenpackagehierarchy")) {
+ } else if (acceptString(FLATTEN_PACKAGE_HIERARCHY)) {
if (configurationBuilder.getPackageObfuscationMode() == PackageObfuscationMode.REPACKAGE) {
- warnOverridingOptions("repackageclasses", "flattenpackagehierarchy", optionStart);
+ warnOverridingOptions(REPACKAGE_CLASSES, FLATTEN_PACKAGE_HIERARCHY, optionStart);
skipWhitespace();
if (isOptionalArgumentGiven()) {
skipSingleArgument();
@@ -469,8 +469,18 @@
configurationBuilder.addRule(rule);
return true;
}
- if (acceptString("nevermerge")) {
- ClassMergingRule rule = parseClassMergingRule(ClassMergingRule.Type.NEVER, optionStart);
+ if (acceptString(NoVerticalClassMergingRule.RULE_NAME)) {
+ ProguardConfigurationRule rule = parseNoVerticalClassMergingRule(optionStart);
+ configurationBuilder.addRule(rule);
+ return true;
+ }
+ if (acceptString(NoHorizontalClassMergingRule.RULE_NAME)) {
+ ProguardConfigurationRule rule = parseNoHorizontalClassMergingRule(optionStart);
+ configurationBuilder.addRule(rule);
+ return true;
+ }
+ if (acceptString(NoStaticClassMergingRule.RULE_NAME)) {
+ ProguardConfigurationRule rule = parseNoStaticClassMergingRule(optionStart);
configurationBuilder.addRule(rule);
return true;
}
@@ -741,10 +751,32 @@
return keepRuleBuilder.build();
}
- private ClassMergingRule parseClassMergingRule(ClassMergingRule.Type type, Position start)
+ private NoVerticalClassMergingRule parseNoVerticalClassMergingRule(Position start)
throws ProguardRuleParserException {
- ClassMergingRule.Builder keepRuleBuilder =
- ClassMergingRule.builder().setOrigin(origin).setStart(start).setType(type);
+ NoVerticalClassMergingRule.Builder keepRuleBuilder =
+ NoVerticalClassMergingRule.builder().setOrigin(origin).setStart(start);
+ parseClassSpec(keepRuleBuilder, false);
+ Position end = getPosition();
+ keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
+ keepRuleBuilder.setEnd(end);
+ return keepRuleBuilder.build();
+ }
+
+ private NoHorizontalClassMergingRule parseNoHorizontalClassMergingRule(Position start)
+ throws ProguardRuleParserException {
+ NoHorizontalClassMergingRule.Builder keepRuleBuilder =
+ NoHorizontalClassMergingRule.builder().setOrigin(origin).setStart(start);
+ parseClassSpec(keepRuleBuilder, false);
+ Position end = getPosition();
+ keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
+ keepRuleBuilder.setEnd(end);
+ return keepRuleBuilder.build();
+ }
+
+ private NoStaticClassMergingRule parseNoStaticClassMergingRule(Position start)
+ throws ProguardRuleParserException {
+ NoStaticClassMergingRule.Builder keepRuleBuilder =
+ NoStaticClassMergingRule.builder().setOrigin(origin).setStart(start);
parseClassSpec(keepRuleBuilder, false);
Position end = getPosition();
keepRuleBuilder.setSource(getSourceSnippet(contents, start, end));
diff --git a/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java b/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
index c8e185f..8313325 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardIfRule.java
@@ -15,7 +15,7 @@
public class ProguardIfRule extends ProguardKeepRuleBase {
- private static final Origin neverInlineOrigin =
+ private static final Origin NEVER_INLINE_ORIGIN =
new Origin(Origin.root()) {
@Override
public String part() {
@@ -23,6 +23,14 @@
}
};
+ private static final Origin NO_HORIZONTAL_CLASS_MERGING_ORIGIN =
+ new Origin(Origin.root()) {
+ @Override
+ public String part() {
+ return "<SYNTHETIC_NO_HORIZONTAL_CLASS_MERGING_RULE>";
+ }
+ };
+
private final Set<DexReference> preconditions;
final ProguardKeepRule subsequentRule;
@@ -156,7 +164,7 @@
protected ClassInlineRule neverClassInlineRuleForCondition(DexItemFactory dexItemFactory) {
return new ClassInlineRule(
- neverInlineOrigin,
+ NEVER_INLINE_ORIGIN,
Position.UNKNOWN,
null,
ProguardTypeMatcher.materializeList(getClassAnnotations(), dexItemFactory),
@@ -201,7 +209,7 @@
return null;
}
return new InlineRule(
- neverInlineOrigin,
+ NEVER_INLINE_ORIGIN,
Position.UNKNOWN,
null,
ProguardTypeMatcher.materializeList(getClassAnnotations(), dexItemFactory),
@@ -222,6 +230,37 @@
InlineRule.Type.NEVER);
}
+ protected NoHorizontalClassMergingRule noHorizontalClassMergingRuleForCondition(
+ DexItemFactory dexItemFactory) {
+ List<ProguardMemberRule> memberRules = null;
+ if (getMemberRules() != null) {
+ memberRules =
+ getMemberRules().stream()
+ .filter(rule -> rule.getRuleType().includesMethods())
+ .map(memberRule -> memberRule.materialize(dexItemFactory))
+ .collect(Collectors.toList());
+ }
+
+ return NoHorizontalClassMergingRule.builder()
+ .setOrigin(NO_HORIZONTAL_CLASS_MERGING_ORIGIN)
+ .addClassAnnotations(
+ ProguardTypeMatcher.materializeList(getClassAnnotations(), dexItemFactory))
+ .setClassAccessFlags(getClassAccessFlags())
+ .setNegatedClassAccessFlags(getNegatedClassAccessFlags())
+ .setClassType(getClassType())
+ .setClassTypeNegated(getClassTypeNegated())
+ .setClassNames(getClassNames().materialize(dexItemFactory))
+ .addInheritanceAnnotations(
+ ProguardTypeMatcher.materializeList(getInheritanceAnnotations(), dexItemFactory))
+ .setInheritanceClassName(
+ getInheritanceClassName() == null
+ ? null
+ : getInheritanceClassName().materialize(dexItemFactory))
+ .setInheritanceIsExtends(getInheritanceIsExtends())
+ .setMemberRules(memberRules)
+ .build();
+ }
+
@Override
public boolean equals(Object o) {
if (!(o instanceof ProguardIfRule)) {
diff --git a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
index db43676..f8b5987 100644
--- a/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/RootSetBuilder.java
@@ -97,7 +97,9 @@
private final Set<DexMethod> neverReprocess = Sets.newIdentityHashSet();
private final PredicateSet<DexType> alwaysClassInline = new PredicateSet<>();
private final Set<DexType> neverClassInline = Sets.newIdentityHashSet();
- private final Set<DexType> neverMerge = Sets.newIdentityHashSet();
+ private final Set<DexType> noVerticalClassMerging = Sets.newIdentityHashSet();
+ private final Set<DexType> noHorizontalClassMerging = Sets.newIdentityHashSet();
+ private final Set<DexType> noStaticClassMerging = Sets.newIdentityHashSet();
private final Set<DexReference> neverPropagateValue = Sets.newIdentityHashSet();
private final Map<DexReference, MutableItemsWithRules> dependentNoShrinking =
new IdentityHashMap<>();
@@ -240,7 +242,9 @@
|| rule instanceof WhyAreYouNotInliningRule) {
markMatchingMethods(clazz, memberKeepRules, rule, null, ifRule);
} else if (rule instanceof ClassInlineRule
- || rule instanceof ClassMergingRule
+ || rule instanceof NoVerticalClassMergingRule
+ || rule instanceof NoHorizontalClassMergingRule
+ || rule instanceof NoStaticClassMergingRule
|| rule instanceof ReprocessClassInitializerRule) {
if (allRulesSatisfied(memberKeepRules, clazz)) {
markClass(clazz, rule, ifRule);
@@ -318,7 +322,9 @@
appView,
subtypingInfo,
alwaysClassInline,
- neverMerge,
+ noVerticalClassMerging,
+ noHorizontalClassMerging,
+ noStaticClassMerging,
alwaysInline,
bypassClinitforInlining);
}
@@ -342,7 +348,9 @@
neverReprocess,
alwaysClassInline,
neverClassInline,
- neverMerge,
+ noVerticalClassMerging,
+ noHorizontalClassMerging,
+ noStaticClassMerging,
neverPropagateValue,
mayHaveSideEffects,
noSideEffects,
@@ -1204,16 +1212,14 @@
throw new Unreachable();
}
context.markAsUsed();
- } else if (context instanceof ClassMergingRule) {
- switch (((ClassMergingRule) context).getType()) {
- case NEVER:
- if (item.isDexClass()) {
- neverMerge.add(item.asDexClass().type);
- }
- break;
- default:
- throw new Unreachable();
- }
+ } else if (context instanceof NoVerticalClassMergingRule) {
+ noVerticalClassMerging.add(item.asDexClass().type);
+ context.markAsUsed();
+ } else if (context instanceof NoHorizontalClassMergingRule) {
+ noHorizontalClassMerging.add(item.asDexClass().type);
+ context.markAsUsed();
+ } else if (context instanceof NoStaticClassMergingRule) {
+ noStaticClassMerging.add(item.asDexClass().type);
context.markAsUsed();
} else if (context instanceof MemberValuePropagationRule) {
switch (((MemberValuePropagationRule) context).getType()) {
@@ -1734,7 +1740,9 @@
public final Set<DexMethod> reprocess;
public final Set<DexMethod> neverReprocess;
public final PredicateSet<DexType> alwaysClassInline;
- public final Set<DexType> neverMerge;
+ public final Set<DexType> noVerticalClassMerging;
+ public final Set<DexType> noHorizontalClassMerging;
+ public final Set<DexType> noStaticClassMerging;
public final Set<DexReference> neverPropagateValue;
public final Map<DexReference, ProguardMemberRule> mayHaveSideEffects;
public final Map<DexReference, ProguardMemberRule> noSideEffects;
@@ -1758,7 +1766,9 @@
Set<DexMethod> neverReprocess,
PredicateSet<DexType> alwaysClassInline,
Set<DexType> neverClassInline,
- Set<DexType> neverMerge,
+ Set<DexType> noVerticalClassMerging,
+ Set<DexType> noHorizontalClassMerging,
+ Set<DexType> noStaticClassMerging,
Set<DexReference> neverPropagateValue,
Map<DexReference, ProguardMemberRule> mayHaveSideEffects,
Map<DexReference, ProguardMemberRule> noSideEffects,
@@ -1787,7 +1797,9 @@
this.reprocess = reprocess;
this.neverReprocess = neverReprocess;
this.alwaysClassInline = alwaysClassInline;
- this.neverMerge = neverMerge;
+ this.noVerticalClassMerging = noVerticalClassMerging;
+ this.noHorizontalClassMerging = noHorizontalClassMerging;
+ this.noStaticClassMerging = noStaticClassMerging;
this.neverPropagateValue = neverPropagateValue;
this.mayHaveSideEffects = mayHaveSideEffects;
this.noSideEffects = noSideEffects;
@@ -1859,7 +1871,9 @@
}
public void pruneDeadItems(DexDefinitionSupplier definitions, Enqueuer enqueuer) {
- pruneDeadReferences(neverMerge, definitions, enqueuer);
+ pruneDeadReferences(noVerticalClassMerging, definitions, enqueuer);
+ pruneDeadReferences(noHorizontalClassMerging, definitions, enqueuer);
+ pruneDeadReferences(noStaticClassMerging, definitions, enqueuer);
pruneDeadReferences(alwaysInline, definitions, enqueuer);
pruneDeadReferences(noSideEffects.keySet(), definitions, enqueuer);
}
diff --git a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
index 3725f5f..abd2a99 100644
--- a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.shaking;
import com.android.tools.r8.FeatureSplit;
-import com.android.tools.r8.features.FeatureSplitConfiguration;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexEncodedField;
import com.android.tools.r8.graph.DexEncodedMethod;
@@ -243,12 +243,12 @@
return null;
}
- private FeatureSplitConfiguration getFeatureSplitConfiguration() {
- return appView.options().featureSplitConfiguration;
+ private ClassToFeatureSplitMap getClassToFeatureSplitMap() {
+ return appView.appInfo().getClassToFeatureSplitMap();
}
private MergeGroup getMergeGroup(DexProgramClass clazz) {
- if (appView.appInfo().neverMerge.contains(clazz.type)) {
+ if (appView.appInfo().getNoStaticClassMergingSet().contains(clazz.type)) {
return MergeGroup.DONT_MERGE;
}
if (clazz.staticFields().size() + clazz.getMethodCollection().size() == 0) {
@@ -303,13 +303,8 @@
}
private MergeKey getMergeKey(DexProgramClass clazz, MergeGroup mergeGroup) {
- FeatureSplitConfiguration featureSplitConfiguration = getFeatureSplitConfiguration();
- FeatureSplit featureSplit =
- featureSplitConfiguration != null
- ? featureSplitConfiguration.getFeatureSplit(clazz)
- : FeatureSplit.BASE;
return new MergeKey(
- featureSplit,
+ getClassToFeatureSplitMap().getFeatureSplit(clazz),
mergeGroup,
mayMergeAcrossPackageBoundaries(clazz)
? MergeKey.GLOBAL
@@ -452,8 +447,7 @@
assert targetClass.accessFlags.isAtLeastAsVisibleAs(sourceClass.accessFlags);
assert sourceClass.instanceFields().isEmpty();
assert targetClass.instanceFields().isEmpty();
- assert getFeatureSplitConfiguration() == null
- || getFeatureSplitConfiguration().inSameFeatureOrBothInBase(sourceClass, targetClass);
+ assert getClassToFeatureSplitMap().isInSameFeatureOrBothInBase(sourceClass, targetClass);
numberOfMergedClasses++;
diff --git a/src/main/java/com/android/tools/r8/shaking/TreePruner.java b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
index 5231fe6..6db253e 100644
--- a/src/main/java/com/android/tools/r8/shaking/TreePruner.java
+++ b/src/main/java/com/android/tools/r8/shaking/TreePruner.java
@@ -110,12 +110,7 @@
Log.debug(getClass(), "Removing class: " + clazz);
}
prunedTypes.add(clazz.type);
- // TODO(b/150118654): It would be nice to add something such as
- // clazz.type.isD8R8SynthesizedType, but such test is currently expensive since it is
- // based on strings, so we check only against the enum unboxing utility class.
- if (clazz.type != appView.dexItemFactory().enumUnboxingUtilityType) {
- unusedItemsPrinter.registerUnusedClass(clazz);
- }
+ unusedItemsPrinter.registerUnusedClass(clazz);
}
}
unusedItemsPrinter.finished();
diff --git a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
index 2d21927..5948028 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -8,7 +8,6 @@
import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
import com.android.tools.r8.errors.Unreachable;
-import com.android.tools.r8.features.FeatureSplitConfiguration;
import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.Code;
@@ -350,7 +349,7 @@
|| allocationInfo.isImmediateInterfaceOfInstantiatedLambda(sourceClass)
|| appInfo.isPinned(sourceClass.type)
|| pinnedTypes.contains(sourceClass.type)
- || appInfo.neverMerge.contains(sourceClass.type)) {
+ || appInfo.getNoVerticalClassMergingSet().contains(sourceClass.type)) {
return false;
}
@@ -358,10 +357,9 @@
.map(DexEncodedMember::toReference)
.noneMatch(appInfo::isPinned);
- FeatureSplitConfiguration featureSplitConfiguration =
- appView.options().featureSplitConfiguration;
- if (featureSplitConfiguration != null
- && !featureSplitConfiguration.inSameFeatureOrBothInBase(sourceClass, targetClass)) {
+ if (!appInfo
+ .getClassToFeatureSplitMap()
+ .isInSameFeatureOrBothInBase(sourceClass, targetClass)) {
return false;
}
if (appView.appServices().allServiceTypes().contains(sourceClass.type)
diff --git a/src/main/java/com/android/tools/r8/synthesis/CommittedItems.java b/src/main/java/com/android/tools/r8/synthesis/CommittedItems.java
new file mode 100644
index 0000000..f6a6245
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/synthesis/CommittedItems.java
@@ -0,0 +1,75 @@
+// Copyright (c) 2020, 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.synthesis;
+
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexType;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import java.util.Collection;
+import java.util.function.Function;
+
+/**
+ * Represents an application with a fully "committed" addition of synthetic items.
+ *
+ * <p>The committed application is used to rebuild application info (see AppInfo and its
+ * derivatives) with the associated additional information for the program at well defined points on
+ * the main thread.
+ *
+ * <p>A committed application will have no pending synthetics that are not defined in the program
+ * classes collection, and it must also satisfy that all synthetic types are indeed contained in the
+ * applications program class collection.
+ */
+public class CommittedItems implements SyntheticDefinitionsProvider {
+
+ // Immutable package accessible fields to allow SyntheticItems creation.
+ final DexApplication application;
+ final int nextSyntheticId;
+ final ImmutableSet<DexType> legacySyntheticTypes;
+ final ImmutableMap<DexType, SyntheticReference> syntheticItems;
+ final ImmutableList<DexType> committedTypes;
+
+ CommittedItems(
+ int nextSyntheticId,
+ DexApplication application,
+ ImmutableSet<DexType> legacySyntheticTypes,
+ ImmutableMap<DexType, SyntheticReference> syntheticItems,
+ ImmutableList<DexType> committedTypes) {
+ assert verifyTypesAreInApp(application, legacySyntheticTypes);
+ assert verifyTypesAreInApp(application, syntheticItems.keySet());
+ this.nextSyntheticId = nextSyntheticId;
+ this.application = application;
+ this.legacySyntheticTypes = legacySyntheticTypes;
+ this.syntheticItems = syntheticItems;
+ this.committedTypes = committedTypes;
+ }
+
+ // Conversion to a mutable synthetic items collection. Should only be used in AppInfo creation.
+ public SyntheticItems toSyntheticItems() {
+ return new SyntheticItems(this);
+ }
+
+ public DexApplication getApplication() {
+ return application;
+ }
+
+ public Collection<DexType> getCommittedTypes() {
+ return committedTypes;
+ }
+
+ @Override
+ public DexClass definitionFor(DexType type, Function<DexType, DexClass> baseDefinitionFor) {
+ // All synthetic types are committed to the application so lookup is just the base lookup.
+ return baseDefinitionFor.apply(type);
+ }
+
+ private static boolean verifyTypesAreInApp(DexApplication app, Collection<DexType> types) {
+ for (DexType type : types) {
+ assert app.programDefinitionFor(type) != null : "Missing synthetic: " + type;
+ }
+ return true;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
new file mode 100644
index 0000000..c03022e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/synthesis/SynthesizingContext.java
@@ -0,0 +1,36 @@
+// Copyright (c) 2020, 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.synthesis;
+
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
+import com.android.tools.r8.origin.Origin;
+
+/**
+ * A synthesizing context is the input type and origin that gives rise to a synthetic item.
+ *
+ * <p>Note that a context can only itself be a synthetic item if it was provided as an input that
+ * was marked as synthetic already, in which case it is its own context. In other words,
+ *
+ * <pre>
+ * for any synthetic item, I:
+ * context(I) == holder(I) iff I is a synthetic input
+ * </pre>
+ *
+ * <p>This class is internal to the synthetic items collection, thus package-protected.
+ */
+class SynthesizingContext {
+ final DexType type;
+ final Origin origin;
+
+ SynthesizingContext(DexType type, Origin origin) {
+ this.type = type;
+ this.origin = origin;
+ }
+
+ SynthesizingContext rewrite(NestedGraphLens lens) {
+ DexType rewritten = lens.lookupType(type);
+ return rewritten == type ? this : new SynthesizingContext(type, origin);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
new file mode 100644
index 0000000..ad04a8d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticClassBuilder.java
@@ -0,0 +1,117 @@
+// Copyright (c) 2020, 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.synthesis;
+
+import com.android.tools.r8.ProgramResource.Kind;
+import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.ClassAccessFlags;
+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.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.EnclosingMethodAttribute;
+import com.android.tools.r8.graph.InnerClassAttribute;
+import com.android.tools.r8.graph.NestHostClassAttribute;
+import com.android.tools.r8.graph.NestMemberClassAttribute;
+import com.android.tools.r8.origin.Origin;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+import java.util.function.Consumer;
+
+public class SyntheticClassBuilder {
+ private final DexItemFactory factory;
+
+ private final DexType type;
+ private final Origin origin;
+
+ private DexType superType;
+ private DexTypeList interfaces = DexTypeList.empty();
+
+ private int nextMethodId = 0;
+ private List<SyntheticMethodBuilder> methods = new ArrayList<>();
+
+ SyntheticClassBuilder(DexType type, SynthesizingContext context, DexItemFactory factory) {
+ this.factory = factory;
+ this.type = type;
+ this.origin = context.origin;
+ this.superType = factory.objectType;
+ }
+
+ public DexItemFactory getFactory() {
+ return factory;
+ }
+
+ public DexType getType() {
+ return type;
+ }
+
+ private String getNextMethodName() {
+ return SyntheticItems.INTERNAL_SYNTHETIC_METHOD_PREFIX + nextMethodId++;
+ }
+
+ public SyntheticClassBuilder addMethod(Consumer<SyntheticMethodBuilder> fn) {
+ SyntheticMethodBuilder method = new SyntheticMethodBuilder(this, getNextMethodName());
+ fn.accept(method);
+ methods.add(method);
+ return this;
+ }
+
+ DexProgramClass build() {
+ ClassAccessFlags accessFlags =
+ ClassAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC);
+ Kind originKind = null;
+ DexString sourceFile = null;
+ NestHostClassAttribute nestHost = null;
+ List<NestMemberClassAttribute> nestMembers = Collections.emptyList();
+ EnclosingMethodAttribute enclosingMembers = null;
+ List<InnerClassAttribute> innerClasses = Collections.emptyList();
+ DexAnnotationSet classAnnotations = DexAnnotationSet.empty();
+ DexEncodedField[] staticFields = DexEncodedField.EMPTY_ARRAY;
+ DexEncodedField[] instanceFields = DexEncodedField.EMPTY_ARRAY;
+ DexEncodedMethod[] directMethods = DexEncodedMethod.EMPTY_ARRAY;
+ DexEncodedMethod[] virtualMethods = DexEncodedMethod.EMPTY_ARRAY;
+ assert !methods.isEmpty();
+ List<DexEncodedMethod> directs = new ArrayList<>(methods.size());
+ List<DexEncodedMethod> virtuals = new ArrayList<>(methods.size());
+ for (SyntheticMethodBuilder builder : methods) {
+ DexEncodedMethod method = builder.build();
+ if (method.isNonPrivateVirtualMethod()) {
+ virtuals.add(method);
+ } else {
+ directs.add(method);
+ }
+ }
+ if (!directs.isEmpty()) {
+ directMethods = directs.toArray(new DexEncodedMethod[directs.size()]);
+ }
+ if (!virtuals.isEmpty()) {
+ virtualMethods = virtuals.toArray(new DexEncodedMethod[virtuals.size()]);
+ }
+ long checksum = 7 * (long) directs.hashCode() + 11 * (long) virtuals.hashCode();
+ return new DexProgramClass(
+ type,
+ originKind,
+ origin,
+ accessFlags,
+ superType,
+ interfaces,
+ sourceFile,
+ nestHost,
+ nestMembers,
+ enclosingMembers,
+ innerClasses,
+ classAnnotations,
+ staticFields,
+ instanceFields,
+ directMethods,
+ virtualMethods,
+ factory.getSkipNameValidationForTesting(),
+ c -> checksum);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java
new file mode 100644
index 0000000..daf936d
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinition.java
@@ -0,0 +1,42 @@
+// Copyright (c) 2020, 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.synthesis;
+
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.origin.Origin;
+import com.google.common.hash.HashCode;
+
+/**
+ * Base type for the defintion of a synthetic item.
+ *
+ * <p>This class is internal to the synthetic items collection, thus package-protected.
+ */
+abstract class SyntheticDefinition {
+ private final SynthesizingContext context;
+
+ SyntheticDefinition(SynthesizingContext context) {
+ this.context = context;
+ }
+
+ abstract SyntheticReference toReference();
+
+ SynthesizingContext getContext() {
+ return context;
+ }
+
+ DexType getContextType() {
+ return context.type;
+ }
+
+ Origin getContextOrigin() {
+ return context.origin;
+ }
+
+ abstract DexProgramClass getHolder();
+
+ abstract HashCode computeHash();
+
+ abstract boolean isEquivalentTo(SyntheticDefinition other);
+}
diff --git a/src/main/java/com/android/tools/r8/graph/SyntheticDefinitionsProvider.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinitionsProvider.java
similarity index 75%
rename from src/main/java/com/android/tools/r8/graph/SyntheticDefinitionsProvider.java
rename to src/main/java/com/android/tools/r8/synthesis/SyntheticDefinitionsProvider.java
index 82e37ab..e66401e 100644
--- a/src/main/java/com/android/tools/r8/graph/SyntheticDefinitionsProvider.java
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticDefinitionsProvider.java
@@ -1,8 +1,10 @@
// Copyright (c) 2020, 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.graph;
+package com.android.tools.r8.synthesis;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexType;
import java.util.function.Function;
public interface SyntheticDefinitionsProvider {
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
new file mode 100644
index 0000000..a2dd07e
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticFinalization.java
@@ -0,0 +1,364 @@
+// Copyright (c) 2020, 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.synthesis;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexAnnotation;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.GraphLens.Builder;
+import com.android.tools.r8.shaking.MainDexClasses;
+import com.android.tools.r8.utils.DescriptorUtils;
+import com.android.tools.r8.utils.InternalOptions;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ListMultimap;
+import com.google.common.hash.HashCode;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.IdentityHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.TreeSet;
+import java.util.function.Predicate;
+
+public class SyntheticFinalization {
+
+ public static class Result {
+ public final CommittedItems commit;
+ public final ImmutableSet<DexType> removedSyntheticClasses;
+
+ public Result(CommittedItems commit, ImmutableSet<DexType> removedSyntheticClasses) {
+ this.commit = commit;
+ this.removedSyntheticClasses = removedSyntheticClasses;
+ }
+ }
+
+ private static class EquivalenceGroup<T extends SyntheticDefinition & Comparable<T>>
+ implements Comparable<EquivalenceGroup<T>> {
+ private List<T> members;
+
+ EquivalenceGroup(T singleton) {
+ this(singleton, Collections.singletonList(singleton));
+ }
+
+ EquivalenceGroup(T representative, List<T> members) {
+ assert !members.isEmpty();
+ assert members.get(0) == representative;
+ this.members = members;
+ }
+
+ T getRepresentative() {
+ return members.get(0);
+ }
+
+ public List<T> getMembers() {
+ return members;
+ }
+
+ @Override
+ public int compareTo(EquivalenceGroup<T> other) {
+ return getRepresentative().compareTo(other.getRepresentative());
+ }
+ }
+
+ private final InternalOptions options;
+ private final ImmutableSet<DexType> legacySyntheticTypes;
+ private final ImmutableMap<DexType, SyntheticReference> syntheticItems;
+
+ SyntheticFinalization(
+ InternalOptions options,
+ ImmutableSet<DexType> legacySyntheticTypes,
+ ImmutableMap<DexType, SyntheticReference> syntheticItems) {
+ this.options = options;
+ this.legacySyntheticTypes = legacySyntheticTypes;
+ this.syntheticItems = syntheticItems;
+ }
+
+ public Result computeFinalSynthetics(AppView<?> appView) {
+ assert verifyNoNestedSynthetics();
+ DexApplication application = appView.appInfo().app();
+ MainDexClasses mainDexClasses = appView.appInfo().getMainDexClasses();
+ GraphLens graphLens = appView.graphLens();
+
+ List<SyntheticMethodDefinition> methodDefinitions =
+ lookupSyntheticMethodDefinitions(application);
+
+ Map<HashCode, List<SyntheticMethodDefinition>> potentialEquivalences =
+ computePotentialEquivalences(methodDefinitions);
+
+ Map<DexType, EquivalenceGroup<SyntheticMethodDefinition>> equivalences =
+ computeActualEquivalences(potentialEquivalences, options.itemFactory);
+
+ Builder lensBuilder = GraphLens.builder();
+ List<DexProgramClass> newProgramClasses = new ArrayList<>();
+ List<DexProgramClass> finalSyntheticClasses = new ArrayList<>();
+ buildLensAndProgram(
+ application,
+ equivalences,
+ syntheticItems::containsKey,
+ mainDexClasses,
+ lensBuilder,
+ options.itemFactory,
+ newProgramClasses,
+ finalSyntheticClasses);
+
+ newProgramClasses.addAll(finalSyntheticClasses);
+
+ handleSynthesizedClassMapping(finalSyntheticClasses, application, options, mainDexClasses);
+
+ DexApplication app = application.builder().replaceProgramClasses(newProgramClasses).build();
+
+ appView.setGraphLens(lensBuilder.build(options.itemFactory, graphLens));
+ assert appView.appInfo().getMainDexClasses() == mainDexClasses;
+ return new Result(
+ new CommittedItems(
+ SyntheticItems.INVALID_ID_AFTER_SYNTHETIC_FINALIZATION,
+ app,
+ legacySyntheticTypes,
+ ImmutableMap.of(),
+ ImmutableList.of()),
+ syntheticItems.keySet());
+ }
+
+ private boolean verifyNoNestedSynthetics() {
+ for (SyntheticReference item : syntheticItems.values()) {
+ // Check that a context is never a synthetic unless it is an input, thus its own context.
+ assert item.getHolder() == item.getContextType()
+ || !syntheticItems.containsKey(item.getContextType());
+ }
+ return true;
+ }
+
+ private void handleSynthesizedClassMapping(
+ List<DexProgramClass> finalSyntheticClasses,
+ DexApplication application,
+ InternalOptions options,
+ MainDexClasses mainDexClasses) {
+ if (options.intermediate) {
+ updateSynthesizedClassMapping(application, finalSyntheticClasses);
+ }
+ updateMainDexListWithSynthesizedClassMap(application, mainDexClasses);
+ if (!options.intermediate) {
+ clearSynthesizedClassMapping(application);
+ }
+ }
+
+ private void updateSynthesizedClassMapping(
+ DexApplication application, List<DexProgramClass> finalSyntheticClasses) {
+ ListMultimap<DexProgramClass, DexProgramClass> originalToSynthesized =
+ ArrayListMultimap.create();
+ for (DexType type : legacySyntheticTypes) {
+ DexProgramClass clazz = DexProgramClass.asProgramClassOrNull(application.definitionFor(type));
+ if (clazz != null) {
+ for (DexProgramClass origin : clazz.getSynthesizedFrom()) {
+ originalToSynthesized.put(origin, clazz);
+ }
+ }
+ }
+ for (DexProgramClass clazz : finalSyntheticClasses) {
+ for (DexProgramClass origin : clazz.getSynthesizedFrom()) {
+ originalToSynthesized.put(origin, clazz);
+ }
+ }
+ for (Map.Entry<DexProgramClass, Collection<DexProgramClass>> entry :
+ originalToSynthesized.asMap().entrySet()) {
+ DexProgramClass original = entry.getKey();
+ // Use a tree set to make sure that we have an ordering on the types.
+ // These types are put in an array in annotations in the output and we
+ // need a consistent ordering on them.
+ TreeSet<DexType> synthesized = new TreeSet<>(DexType::slowCompareTo);
+ entry.getValue().stream()
+ .map(dexProgramClass -> dexProgramClass.type)
+ .forEach(synthesized::add);
+ synthesized.addAll(
+ DexAnnotation.readAnnotationSynthesizedClassMap(original, application.dexItemFactory));
+
+ DexAnnotation updatedAnnotation =
+ DexAnnotation.createAnnotationSynthesizedClassMap(
+ synthesized, application.dexItemFactory);
+
+ original.setAnnotations(original.annotations().getWithAddedOrReplaced(updatedAnnotation));
+ }
+ }
+
+ private void updateMainDexListWithSynthesizedClassMap(
+ DexApplication application, MainDexClasses mainDexClasses) {
+ if (mainDexClasses.isEmpty()) {
+ return;
+ }
+ List<DexProgramClass> newMainDexClasses = new ArrayList<>();
+ mainDexClasses.forEach(
+ dexType -> {
+ DexProgramClass programClass =
+ DexProgramClass.asProgramClassOrNull(application.definitionFor(dexType));
+ if (programClass != null) {
+ Collection<DexType> derived =
+ DexAnnotation.readAnnotationSynthesizedClassMap(
+ programClass, application.dexItemFactory);
+ for (DexType type : derived) {
+ DexProgramClass syntheticClass =
+ DexProgramClass.asProgramClassOrNull(application.definitionFor(type));
+ if (syntheticClass != null) {
+ newMainDexClasses.add(syntheticClass);
+ }
+ }
+ }
+ });
+ mainDexClasses.addAll(newMainDexClasses);
+ }
+
+ private void clearSynthesizedClassMapping(DexApplication application) {
+ for (DexProgramClass clazz : application.classes()) {
+ clazz.setAnnotations(
+ clazz.annotations().getWithout(application.dexItemFactory.annotationSynthesizedClassMap));
+ }
+ }
+
+ private static void buildLensAndProgram(
+ DexApplication app,
+ Map<DexType, EquivalenceGroup<SyntheticMethodDefinition>> syntheticMethodGroups,
+ Predicate<DexType> isSyntheticType,
+ MainDexClasses mainDexClasses,
+ Builder lensBuilder,
+ DexItemFactory factory,
+ List<DexProgramClass> normalClasses,
+ List<DexProgramClass> newSyntheticClasses) {
+
+ for (DexProgramClass clazz : app.classes()) {
+ if (!isSyntheticType.test(clazz.type)) {
+ normalClasses.add(clazz);
+ }
+ }
+
+ syntheticMethodGroups.forEach(
+ (syntheticType, syntheticGroup) -> {
+ SyntheticMethodDefinition firstMember = syntheticGroup.getRepresentative();
+ SynthesizingContext context = firstMember.getContext();
+ SyntheticClassBuilder builder =
+ new SyntheticClassBuilder(syntheticType, context, factory);
+ // TODO(b/158159959): Support grouping multiple methods per synthetic class.
+ builder.addMethod(
+ methodBuilder -> {
+ DexEncodedMethod definition = firstMember.getMethod().getDefinition();
+ methodBuilder
+ .setAccessFlags(definition.accessFlags)
+ .setProto(definition.getProto())
+ .setCode(m -> definition.getCode());
+ });
+ DexProgramClass externalSyntheticClass = builder.build();
+ assert externalSyntheticClass.getMethodCollection().size() == 1;
+ DexEncodedMethod externalSyntheticMethod =
+ externalSyntheticClass.methods().iterator().next();
+ newSyntheticClasses.add(externalSyntheticClass);
+ for (SyntheticMethodDefinition member : syntheticGroup.getMembers()) {
+ lensBuilder.map(
+ member.getMethod().getHolder().getType(), externalSyntheticClass.getType());
+ lensBuilder.map(member.getMethod().getReference(), externalSyntheticMethod.method);
+ DexType memberContext = member.getContextType();
+ DexProgramClass from =
+ DexProgramClass.asProgramClassOrNull(app.definitionFor(memberContext));
+ if (from != null) {
+ externalSyntheticClass.addSynthesizedFrom(from);
+ if (mainDexClasses.contains(from)) {
+ mainDexClasses.add(externalSyntheticClass);
+ }
+ }
+ }
+ });
+ }
+
+ private static <T extends SyntheticDefinition & Comparable<T>>
+ Map<DexType, EquivalenceGroup<T>> computeActualEquivalences(
+ Map<HashCode, List<T>> potentialEquivalences, DexItemFactory factory) {
+ Map<DexType, List<EquivalenceGroup<T>>> groupsPerContext = new IdentityHashMap<>();
+ potentialEquivalences.forEach(
+ (hash, members) -> {
+ // Get a representative member and add to its group.
+ T representative = findDeterministicRepresentative(members);
+ List<T> group = new ArrayList<>(members.size());
+ group.add(representative);
+ // Each other member is in the shared group if it is actually equal to the first member.
+ for (T member : members) {
+ if (member != representative) {
+ if (member.isEquivalentTo(representative)) {
+ group.add(member);
+ } else {
+ // The member becomes a new singleton group.
+ // TODO(b/158159959): Consider checking for sub-groups of matching members.
+ groupsPerContext
+ .computeIfAbsent(member.getContextType(), k -> new ArrayList<>())
+ .add(new EquivalenceGroup<>(member));
+ }
+ }
+ }
+ groupsPerContext
+ .computeIfAbsent(representative.getContextType(), k -> new ArrayList<>())
+ .add(new EquivalenceGroup<>(representative, group));
+ });
+ Map<DexType, EquivalenceGroup<T>> equivalences = new IdentityHashMap<>();
+ groupsPerContext.forEach(
+ (context, groups) -> {
+ groups.sort(EquivalenceGroup::compareTo);
+ for (int i = 0; i < groups.size(); i++) {
+ equivalences.put(createExternalType(context, i, factory), groups.get(i));
+ }
+ });
+ return equivalences;
+ }
+
+ private static <T extends SyntheticDefinition & Comparable<T>> T findDeterministicRepresentative(
+ List<T> members) {
+ // Pick a deterministic member as representative.
+ T smallest = members.get(0);
+ for (int i = 1; i < members.size(); i++) {
+ T next = members.get(i);
+ if (next.compareTo(smallest) < 0) {
+ smallest = next;
+ }
+ }
+ return smallest;
+ }
+
+ private static DexType createExternalType(
+ DexType representativeContext, int nextContextId, DexItemFactory factory) {
+ return factory.createType(
+ DescriptorUtils.getDescriptorFromClassBinaryName(
+ representativeContext.getInternalName()
+ + SyntheticItems.EXTERNAL_SYNTHETIC_CLASS_SEPARATOR
+ + nextContextId));
+ }
+
+ private static <T extends SyntheticDefinition>
+ Map<HashCode, List<T>> computePotentialEquivalences(List<T> definitions) {
+ Map<HashCode, List<T>> equivalences = new HashMap<>(definitions.size());
+ for (T definition : definitions) {
+ HashCode hash = definition.computeHash();
+ equivalences.computeIfAbsent(hash, k -> new ArrayList<>()).add(definition);
+ }
+ return equivalences;
+ }
+
+ private List<SyntheticMethodDefinition> lookupSyntheticMethodDefinitions(
+ DexApplication finalApp) {
+ List<SyntheticMethodDefinition> methods = new ArrayList<>(syntheticItems.size());
+ for (SyntheticReference reference : syntheticItems.values()) {
+ SyntheticDefinition definition = reference.lookupDefinition(finalApp::definitionFor);
+ assert definition != null;
+ assert definition instanceof SyntheticMethodDefinition;
+ if (definition != null && definition instanceof SyntheticMethodDefinition) {
+ methods.add(((SyntheticMethodDefinition) definition));
+ }
+ }
+ return methods;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
new file mode 100644
index 0000000..b3c179f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticItems.java
@@ -0,0 +1,360 @@
+// Copyright (c) 2020, 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.synthesis;
+
+import com.android.tools.r8.errors.InternalCompilerError;
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.synthesis.SyntheticFinalization.Result;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.ImmutableSet.Builder;
+import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+public class SyntheticItems implements SyntheticDefinitionsProvider {
+
+ static final int INVALID_ID_AFTER_SYNTHETIC_FINALIZATION = -1;
+
+ /**
+ * The internal synthetic class separator is only used for representing synthetic items during
+ * compilation. In particular, this separator must never be used to write synthetic classes to the
+ * final compilation result.
+ */
+ public static final String INTERNAL_SYNTHETIC_CLASS_SEPARATOR = "-$$InternalSynthetic";
+
+ /**
+ * The external synthetic class separator is used when writing classes. It may appear in types
+ * during compilation as the output of a compilation may be the input to another.
+ */
+ public static final String EXTERNAL_SYNTHETIC_CLASS_SEPARATOR = "-$$ExternalSynthetic";
+
+ /** Method prefix when generating synthetic methods in a class. */
+ static final String INTERNAL_SYNTHETIC_METHOD_PREFIX = "m";
+
+ public static boolean verifyNotInternalSynthetic(DexType type) {
+ assert !type.toDescriptorString().contains(SyntheticItems.INTERNAL_SYNTHETIC_CLASS_SEPARATOR);
+ return true;
+ }
+
+ /** Globally incremented id for the next internal synthetic class. */
+ private int nextSyntheticId;
+
+ /**
+ * Thread safe collection of synthesized classes that are not yet committed to the application.
+ * TODO(b/158159959): Remove legacy support.
+ */
+ private final Map<DexType, DexProgramClass> legacyPendingClasses = new ConcurrentHashMap<>();
+
+ /**
+ * Immutable set of synthetic types in the application (eg, committed). TODO(b/158159959): Remove
+ * legacy support.
+ */
+ private final ImmutableSet<DexType> legacySyntheticTypes;
+
+ /** Thread safe collection of synthetic items not yet committed to the application. */
+ private final ConcurrentHashMap<DexType, SyntheticDefinition> pendingDefinitions =
+ new ConcurrentHashMap<>();
+
+ /** Mapping from synthetic type to its synthetic description. */
+ private final ImmutableMap<DexType, SyntheticReference> nonLecacySyntheticItems;
+
+ // Only for use from initial AppInfo/AppInfoWithClassHierarchy create functions. */
+ public static SyntheticItems createInitialSyntheticItems() {
+ return new SyntheticItems(0, ImmutableSet.of(), ImmutableMap.of());
+ }
+
+ // Only for conversion to a mutable synthetic items collection.
+ SyntheticItems(CommittedItems commit) {
+ this(commit.nextSyntheticId, commit.legacySyntheticTypes, commit.syntheticItems);
+ }
+
+ private SyntheticItems(
+ int nextSyntheticId,
+ ImmutableSet<DexType> legacySyntheticTypes,
+ ImmutableMap<DexType, SyntheticReference> nonLecacySyntheticItems) {
+ this.nextSyntheticId = nextSyntheticId;
+ this.legacySyntheticTypes = legacySyntheticTypes;
+ this.nonLecacySyntheticItems = nonLecacySyntheticItems;
+ assert nonLecacySyntheticItems.keySet().stream()
+ .noneMatch(
+ t -> t.toDescriptorString().endsWith(getSyntheticDescriptorSuffix(nextSyntheticId)));
+ assert Sets.intersection(nonLecacySyntheticItems.keySet(), legacySyntheticTypes).isEmpty();
+ }
+
+ // Internal synthetic id creation helpers.
+
+ private synchronized int getNextSyntheticId() {
+ if (nextSyntheticId == INVALID_ID_AFTER_SYNTHETIC_FINALIZATION) {
+ throw new InternalCompilerError(
+ "Unexpected attempt to synthesize classes after synthetic finalization.");
+ }
+ return nextSyntheticId++;
+ }
+
+ private static DexType hygienicType(
+ DexItemFactory factory, int syntheticId, SynthesizingContext context) {
+ String contextDesc = context.type.toDescriptorString();
+ String prefix = contextDesc.substring(0, contextDesc.length() - 1);
+ String syntheticDesc = prefix + getSyntheticDescriptorSuffix(syntheticId);
+ return factory.createType(syntheticDesc);
+ }
+
+ private static String getSyntheticDescriptorSuffix(int syntheticId) {
+ return INTERNAL_SYNTHETIC_CLASS_SEPARATOR + syntheticId + ";";
+ }
+
+ // Predicates and accessors.
+
+ @Override
+ public DexClass definitionFor(DexType type, Function<DexType, DexClass> baseDefinitionFor) {
+ DexProgramClass pending = legacyPendingClasses.get(type);
+ if (pending == null) {
+ SyntheticDefinition item = pendingDefinitions.get(type);
+ if (item != null) {
+ pending = item.getHolder();
+ }
+ }
+ if (pending != null) {
+ assert baseDefinitionFor.apply(type) == null
+ : "Pending synthetic definition also present in the active program: " + type;
+ return pending;
+ }
+ return baseDefinitionFor.apply(type);
+ }
+
+ public boolean hasPendingSyntheticClasses() {
+ return !legacyPendingClasses.isEmpty() || !pendingDefinitions.isEmpty();
+ }
+
+ public Collection<DexProgramClass> getPendingSyntheticClasses() {
+ List<DexProgramClass> pending =
+ new ArrayList<>(pendingDefinitions.size() + legacyPendingClasses.size());
+ for (SyntheticDefinition item : pendingDefinitions.values()) {
+ pending.add(item.getHolder());
+ }
+ pending.addAll(legacyPendingClasses.values());
+ return Collections.unmodifiableList(pending);
+ }
+
+ private boolean isCommittedSynthetic(DexType type) {
+ return nonLecacySyntheticItems.containsKey(type) || legacySyntheticTypes.contains(type);
+ }
+
+ public boolean isPendingSynthetic(DexType type) {
+ return pendingDefinitions.containsKey(type) || legacyPendingClasses.containsKey(type);
+ }
+
+ public boolean isSyntheticClass(DexType type) {
+ return isCommittedSynthetic(type)
+ || isPendingSynthetic(type)
+ // TODO(b/158159959): Remove usage of name-based identification.
+ || type.isD8R8SynthesizedClassType();
+ }
+
+ public boolean isSyntheticClass(DexProgramClass clazz) {
+ return isSyntheticClass(clazz.type);
+ }
+
+ public Collection<DexProgramClass> getLegacyPendingClasses() {
+ return Collections.unmodifiableCollection(legacyPendingClasses.values());
+ }
+
+ private SynthesizingContext getSynthesizingContext(DexProgramClass context) {
+ SyntheticDefinition pendingItemContext = pendingDefinitions.get(context.type);
+ if (pendingItemContext != null) {
+ return pendingItemContext.getContext();
+ }
+ SyntheticReference committedItemContext = nonLecacySyntheticItems.get(context.type);
+ return committedItemContext != null
+ ? committedItemContext.getContext()
+ : new SynthesizingContext(context.type, context.origin);
+ }
+
+ // Addition and creation of synthetic items.
+
+ // TODO(b/158159959): Remove the usage of this direct class addition (and name-based id).
+ public void addLegacySyntheticClass(DexProgramClass clazz) {
+ assert clazz.type.isD8R8SynthesizedClassType();
+ assert !isCommittedSynthetic(clazz.type);
+ DexProgramClass previous = legacyPendingClasses.put(clazz.type, clazz);
+ assert previous == null || previous == clazz;
+ }
+
+ /** Create a single synthetic method item. */
+ public ProgramMethod createMethod(
+ DexProgramClass context, DexItemFactory factory, Consumer<SyntheticMethodBuilder> fn) {
+ // Obtain the outer synthesizing context in the case the context itself is synthetic.
+ // The is to ensure a flat input-type -> synthetic-item mapping.
+ SynthesizingContext outerContext = getSynthesizingContext(context);
+ DexType type = hygienicType(factory, getNextSyntheticId(), outerContext);
+ DexProgramClass clazz =
+ new SyntheticClassBuilder(type, outerContext, factory).addMethod(fn).build();
+ ProgramMethod method = new ProgramMethod(clazz, clazz.methods().iterator().next());
+ addPendingDefinition(new SyntheticMethodDefinition(outerContext, method));
+ return method;
+ }
+
+ private void addPendingDefinition(SyntheticDefinition definition) {
+ pendingDefinitions.put(definition.getHolder().getType(), definition);
+ }
+
+ // Commit of the synthetic items to a new fully populated application.
+
+ public CommittedItems commit(DexApplication application) {
+ return commitPrunedClasses(application, Collections.emptySet());
+ }
+
+ public CommittedItems commitPrunedClasses(
+ DexApplication application, Set<DexType> removedClasses) {
+ return commit(
+ application,
+ removedClasses,
+ legacyPendingClasses,
+ legacySyntheticTypes,
+ pendingDefinitions,
+ nonLecacySyntheticItems,
+ nextSyntheticId);
+ }
+
+ public CommittedItems commitRewrittenWithLens(DexApplication application, NestedGraphLens lens) {
+ // Rewrite the previously committed synthetic types.
+ ImmutableSet<DexType> rewrittenLegacyTypes = lens.rewriteTypes(this.legacySyntheticTypes);
+ ImmutableMap.Builder<DexType, SyntheticReference> rewrittenItems = ImmutableMap.builder();
+ for (SyntheticReference reference : nonLecacySyntheticItems.values()) {
+ SyntheticReference rewritten = reference.rewrite(lens);
+ rewrittenItems.put(rewritten.getHolder(), rewritten);
+ }
+ // No pending item should need rewriting.
+ assert legacyPendingClasses.keySet().equals(lens.rewriteTypes(legacyPendingClasses.keySet()));
+ assert pendingDefinitions.keySet().equals(lens.rewriteTypes(pendingDefinitions.keySet()));
+ return commit(
+ application,
+ Collections.emptySet(),
+ legacyPendingClasses,
+ rewrittenLegacyTypes,
+ pendingDefinitions,
+ rewrittenItems.build(),
+ nextSyntheticId);
+ }
+
+ private static CommittedItems commit(
+ DexApplication application,
+ Set<DexType> removedClasses,
+ Map<DexType, DexProgramClass> legacyPendingClasses,
+ ImmutableSet<DexType> legacySyntheticTypes,
+ ConcurrentHashMap<DexType, SyntheticDefinition> pendingDefinitions,
+ ImmutableMap<DexType, SyntheticReference> syntheticItems,
+ int nextSyntheticId) {
+ // Legacy synthetics must already have been committed.
+ assert verifyClassesAreInApp(application, legacyPendingClasses.values());
+ // Add the set of legacy definitions to the synthetic types.
+ ImmutableSet<DexType> mergedLegacyTypes = legacySyntheticTypes;
+ if (!legacyPendingClasses.isEmpty() || !removedClasses.isEmpty()) {
+ ImmutableSet.Builder<DexType> legacyBuilder = ImmutableSet.builder();
+ filteredAdd(legacySyntheticTypes, removedClasses, legacyBuilder);
+ filteredAdd(legacyPendingClasses.keySet(), removedClasses, legacyBuilder);
+ mergedLegacyTypes = legacyBuilder.build();
+ }
+ // The set of synthetic items is the union of the previous types plus the pending additions.
+ ImmutableMap<DexType, SyntheticReference> mergedItems;
+ ImmutableList<DexType> additions;
+ DexApplication amendedApplication;
+ if (pendingDefinitions.isEmpty()) {
+ mergedItems = filteredCopy(syntheticItems, removedClasses);
+ additions = ImmutableList.of();
+ amendedApplication = application;
+ } else {
+ DexApplication.Builder<?> appBuilder = application.builder();
+ ImmutableMap.Builder<DexType, SyntheticReference> itemsBuilder = ImmutableMap.builder();
+ ImmutableList.Builder<DexType> additionsBuilder = ImmutableList.builder();
+ for (SyntheticDefinition definition : pendingDefinitions.values()) {
+ if (removedClasses.contains(definition.getHolder().getType())) {
+ continue;
+ }
+ SyntheticReference reference = definition.toReference();
+ itemsBuilder.put(reference.getHolder(), reference);
+ additionsBuilder.add(definition.getHolder().getType());
+ appBuilder.addProgramClass(definition.getHolder());
+ }
+ filteredAdd(syntheticItems, removedClasses, itemsBuilder);
+ mergedItems = itemsBuilder.build();
+ additions = additionsBuilder.build();
+ amendedApplication = appBuilder.build();
+ }
+ return new CommittedItems(
+ nextSyntheticId, amendedApplication, mergedLegacyTypes, mergedItems, additions);
+ }
+
+ private static void filteredAdd(
+ Set<DexType> input, Set<DexType> excludeSet, Builder<DexType> result) {
+ if (excludeSet.isEmpty()) {
+ result.addAll(input);
+ } else {
+ for (DexType type : input) {
+ if (!excludeSet.contains(type)) {
+ result.add(type);
+ }
+ }
+ }
+ }
+
+ private static ImmutableMap<DexType, SyntheticReference> filteredCopy(
+ ImmutableMap<DexType, SyntheticReference> syntheticItems, Set<DexType> removedClasses) {
+ if (removedClasses.isEmpty()) {
+ return syntheticItems;
+ }
+ ImmutableMap.Builder<DexType, SyntheticReference> builder = ImmutableMap.builder();
+ filteredAdd(syntheticItems, removedClasses, builder);
+ return builder.build();
+ }
+
+ private static void filteredAdd(
+ ImmutableMap<DexType, SyntheticReference> syntheticItems,
+ Set<DexType> removedClasses,
+ ImmutableMap.Builder<DexType, SyntheticReference> builder) {
+ if (removedClasses.isEmpty()) {
+ builder.putAll(syntheticItems);
+ } else {
+ syntheticItems.forEach(
+ (t, r) -> {
+ if (!removedClasses.contains(t)) {
+ builder.put(t, r);
+ }
+ });
+ }
+ }
+
+ private static boolean verifyClassesAreInApp(
+ DexApplication app, Collection<DexProgramClass> classes) {
+ for (DexProgramClass clazz : classes) {
+ assert app.programDefinitionFor(clazz.type) != null : "Missing synthetic: " + clazz.type;
+ }
+ return true;
+ }
+
+ // Finalization of synthetic items.
+
+ public Result computeFinalSynthetics(AppView<?> appView) {
+ assert !hasPendingSyntheticClasses();
+ return new SyntheticFinalization(
+ appView.options(), legacySyntheticTypes, nonLecacySyntheticItems)
+ .computeFinalSynthetics(appView);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
new file mode 100644
index 0000000..90e593c
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodBuilder.java
@@ -0,0 +1,77 @@
+// Copyright (c) 2020, 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.synthesis;
+
+import com.android.tools.r8.graph.Code;
+import com.android.tools.r8.graph.DexAnnotationSet;
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.MethodAccessFlags;
+import com.android.tools.r8.graph.ParameterAnnotationsList;
+
+public class SyntheticMethodBuilder {
+
+ public interface SyntheticCodeGenerator {
+ Code generate(DexMethod method);
+ }
+
+ private final SyntheticClassBuilder parent;
+ private final String name;
+ private DexProto proto = null;
+ private SyntheticCodeGenerator codeGenerator = null;
+ private MethodAccessFlags accessFlags = null;
+
+ SyntheticMethodBuilder(SyntheticClassBuilder parent, String name) {
+ this.parent = parent;
+ this.name = name;
+ }
+
+ public SyntheticMethodBuilder setProto(DexProto proto) {
+ this.proto = proto;
+ return this;
+ }
+
+ public SyntheticMethodBuilder setCode(SyntheticCodeGenerator codeGenerator) {
+ this.codeGenerator = codeGenerator;
+ return this;
+ }
+
+ public SyntheticMethodBuilder setAccessFlags(MethodAccessFlags accessFlags) {
+ this.accessFlags = accessFlags;
+ return this;
+ }
+
+ DexEncodedMethod build() {
+ boolean isCompilerSynthesized = true;
+ DexMethod methodSignature = getMethodSignature();
+ return new DexEncodedMethod(
+ methodSignature,
+ getAccessFlags(),
+ getAnnotations(),
+ getParameterAnnotations(),
+ getCodeObject(methodSignature),
+ isCompilerSynthesized);
+ }
+
+ private DexMethod getMethodSignature() {
+ return parent.getFactory().createMethod(parent.getType(), proto, name);
+ }
+
+ private MethodAccessFlags getAccessFlags() {
+ return accessFlags;
+ }
+
+ private DexAnnotationSet getAnnotations() {
+ return DexAnnotationSet.empty();
+ }
+
+ private ParameterAnnotationsList getParameterAnnotations() {
+ return ParameterAnnotationsList.empty();
+ }
+
+ private Code getCodeObject(DexMethod methodSignature) {
+ return codeGenerator.generate(methodSignature);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodDefinition.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodDefinition.java
new file mode 100644
index 0000000..6fb07c5
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodDefinition.java
@@ -0,0 +1,67 @@
+// Copyright (c) 2020, 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.synthesis;
+
+import com.android.tools.r8.graph.DexEncodedMethod;
+import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.google.common.hash.HashCode;
+import com.google.common.hash.Hasher;
+import com.google.common.hash.Hashing;
+import java.util.Comparator;
+
+/**
+ * Definition of a synthetic method item.
+ *
+ * <p>This class is internal to the synthetic items collection, thus package-protected.
+ */
+class SyntheticMethodDefinition extends SyntheticDefinition
+ implements Comparable<SyntheticMethodDefinition> {
+
+ private final ProgramMethod method;
+
+ SyntheticMethodDefinition(SynthesizingContext context, ProgramMethod method) {
+ super(context);
+ this.method = method;
+ }
+
+ public ProgramMethod getMethod() {
+ return method;
+ }
+
+ @Override
+ SyntheticReference toReference() {
+ return new SyntheticMethodReference(getContext(), method.getReference());
+ }
+
+ @Override
+ DexProgramClass getHolder() {
+ return method.getHolder();
+ }
+
+ @Override
+ HashCode computeHash() {
+ Hasher hasher = Hashing.sha256().newHasher();
+ method.getDefinition().hashSyntheticContent(hasher);
+ return hasher.hash();
+ }
+
+ @Override
+ boolean isEquivalentTo(SyntheticDefinition other) {
+ if (!(other instanceof SyntheticMethodDefinition)) {
+ return false;
+ }
+ SyntheticMethodDefinition o = (SyntheticMethodDefinition) other;
+ return method.getDefinition().isSyntheticContentEqual(o.method.getDefinition());
+ }
+
+ // Since methods are sharable they must define an order from which representatives can be found.
+ @Override
+ public int compareTo(SyntheticMethodDefinition other) {
+ return Comparator.comparing(SyntheticMethodDefinition::getContextType, DexType::slowCompareTo)
+ .thenComparing(m -> m.method.getDefinition(), DexEncodedMethod::syntheticCompareTo)
+ .compare(this, other);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java
new file mode 100644
index 0000000..326eee0
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticMethodReference.java
@@ -0,0 +1,50 @@
+// Copyright (c) 2020, 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.synthesis;
+
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
+import com.android.tools.r8.graph.ProgramMethod;
+import java.util.function.Function;
+
+/**
+ * Reference to a synthetic method item.
+ *
+ * <p>This class is internal to the synthetic items collection, thus package-protected.
+ */
+class SyntheticMethodReference extends SyntheticReference {
+ final DexMethod method;
+
+ SyntheticMethodReference(SynthesizingContext context, DexMethod method) {
+ super(context);
+ this.method = method;
+ }
+
+ @Override
+ DexType getHolder() {
+ return method.holder;
+ }
+
+ @Override
+ SyntheticDefinition lookupDefinition(Function<DexType, DexClass> definitions) {
+ DexClass clazz = definitions.apply(method.holder);
+ if (clazz == null) {
+ return null;
+ }
+ assert clazz.isProgramClass();
+ ProgramMethod definition = clazz.asProgramClass().lookupProgramMethod(this.method);
+ return new SyntheticMethodDefinition(getContext(), definition);
+ }
+
+ @Override
+ SyntheticReference rewrite(NestedGraphLens lens) {
+ SynthesizingContext context = getContext().rewrite(lens);
+ DexMethod rewritten = lens.lookupMethod(method);
+ return context == getContext() && rewritten == method
+ ? this
+ : new SyntheticMethodReference(context, method);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/synthesis/SyntheticReference.java b/src/main/java/com/android/tools/r8/synthesis/SyntheticReference.java
new file mode 100644
index 0000000..9981624
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/synthesis/SyntheticReference.java
@@ -0,0 +1,41 @@
+// Copyright (c) 2020, 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.synthesis;
+
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
+import com.android.tools.r8.origin.Origin;
+import java.util.function.Function;
+
+/**
+ * Base type for a reference to a synthetic item.
+ *
+ * <p>This class is internal to the synthetic items collection, thus package-protected.
+ */
+abstract class SyntheticReference {
+ private final SynthesizingContext context;
+
+ SyntheticReference(SynthesizingContext context) {
+ this.context = context;
+ }
+
+ abstract SyntheticDefinition lookupDefinition(Function<DexType, DexClass> definitions);
+
+ final SynthesizingContext getContext() {
+ return context;
+ }
+
+ final DexType getContextType() {
+ return context.type;
+ }
+
+ final Origin getContextOrigin() {
+ return context.origin;
+ }
+
+ abstract DexType getHolder();
+
+ abstract SyntheticReference rewrite(NestedGraphLens lens);
+}
diff --git a/src/main/java/com/android/tools/r8/utils/AndroidApp.java b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
index c23e47d..0164b4e 100644
--- a/src/main/java/com/android/tools/r8/utils/AndroidApp.java
+++ b/src/main/java/com/android/tools/r8/utils/AndroidApp.java
@@ -32,7 +32,10 @@
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.features.FeatureSplitConfiguration;
+import com.android.tools.r8.graph.DexItemFactory;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.origin.ArchiveEntryOrigin;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.PathOrigin;
@@ -472,7 +475,7 @@
dumpFeatureSplitFileNames(options.featureSplitConfiguration),
nextDexIndex,
out,
- options.featureSplitConfiguration);
+ options);
nextDexIndex = dumpClasspathResources(nextDexIndex, out);
nextDexIndex = dumpLibraryResources(nextDexIndex, out);
} catch (IOException | ResourceException e) {
@@ -534,12 +537,16 @@
Map<FeatureSplit, String> featureSplitArchiveNames,
int nextDexIndex,
ZipOutputStream out,
- FeatureSplitConfiguration featureSplitConfiguration)
+ InternalOptions options)
throws IOException, ResourceException {
Map<FeatureSplit, ByteArrayOutputStream> featureSplitArchiveByteStreams =
new IdentityHashMap<>();
Map<FeatureSplit, ZipOutputStream> featureSplitArchiveOutputStreams = new IdentityHashMap<>();
try {
+ DexItemFactory dexItemFactory = options.dexItemFactory();
+ FeatureSplitConfiguration featureSplitConfiguration = options.featureSplitConfiguration;
+ ClassToFeatureSplitMap classToFeatureSplitMap =
+ ClassToFeatureSplitMap.createInitialClassToFeatureSplitMap(options);
if (featureSplitConfiguration != null) {
for (FeatureSplit featureSplit : featureSplitConfiguration.getFeatureSplits()) {
ByteArrayOutputStream archiveByteStream = new ByteArrayOutputStream();
@@ -567,9 +574,8 @@
nextDexIndex,
classDescriptor -> {
if (featureSplitConfiguration != null) {
- FeatureSplit featureSplit =
- featureSplitConfiguration.getFeatureSplitFromClassDescriptor(
- classDescriptor);
+ DexType type = dexItemFactory.createType(classDescriptor);
+ FeatureSplit featureSplit = classToFeatureSplitMap.getFeatureSplit(type);
if (featureSplit != null) {
return featureSplitArchiveOutputStreams.get(featureSplit);
}
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 a9d5c3d..cf31dec 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -104,6 +104,10 @@
public final DexItemFactory itemFactory;
+ public DexItemFactory dexItemFactory() {
+ return itemFactory;
+ }
+
public boolean hasProguardConfiguration() {
return proguardConfiguration != null;
}
@@ -370,7 +374,7 @@
}
public boolean shouldBackportMethods() {
- return !hasConsumer() || isGeneratingDex();
+ return !hasConsumer() || isGeneratingDex() || cfToCfDesugar;
}
public boolean shouldKeepStackMapTable() {
diff --git a/src/test/java/com/android/tools/r8/DesugarTestBuilder.java b/src/test/java/com/android/tools/r8/DesugarTestBuilder.java
new file mode 100644
index 0000000..33ef940
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/DesugarTestBuilder.java
@@ -0,0 +1,44 @@
+// Copyright (c) 2020, 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;
+
+import com.android.tools.r8.utils.Pair;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+
+public class DesugarTestBuilder
+ extends TestBuilderCollection<
+ DesugarTestConfiguration, DesugarTestRunResult, DesugarTestBuilder> {
+
+ public static DesugarTestBuilder create(
+ TestState state,
+ List<Pair<DesugarTestConfiguration, TestBuilder<? extends TestRunResult<?>, ?>>>
+ testBuilders) {
+ return new DesugarTestBuilder(state, testBuilders);
+ }
+
+ private DesugarTestBuilder(
+ TestState state,
+ List<Pair<DesugarTestConfiguration, TestBuilder<? extends TestRunResult<?>, ?>>> builders) {
+ super(state, builders);
+ }
+
+ @Override
+ DesugarTestBuilder self() {
+ return this;
+ }
+
+ @Override
+ public DesugarTestRunResult run(TestRuntime runtime, String mainClass, String... args)
+ throws CompilationFailedException, ExecutionException, IOException {
+ List<Pair<DesugarTestConfiguration, TestRunResult<?>>> runs = new ArrayList<>(builders.size());
+ for (Pair<DesugarTestConfiguration, TestBuilder<? extends TestRunResult<?>, ?>> builder :
+ builders) {
+ runs.add(new Pair<>(builder.getFirst(), builder.getSecond().run(runtime, mainClass, args)));
+ }
+ return DesugarTestRunResult.create(runs);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/DesugarTestConfiguration.java b/src/test/java/com/android/tools/r8/DesugarTestConfiguration.java
new file mode 100644
index 0000000..c748ad3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/DesugarTestConfiguration.java
@@ -0,0 +1,32 @@
+// Copyright (c) 2020, 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;
+
+/** The configurations for a desugar test */
+public enum DesugarTestConfiguration {
+ // Javac generated code with no desugaring (reference run).
+ JAVAC,
+ // Javac generated code with desugaring to class file.
+ D8_CF,
+ // Javac generated code with desugaring to DEX.
+ D8_DEX,
+ // Javac generated code with desugaring to class file and then compiled to DEX without desugaring.
+ D8_CF_D8_DEX;
+
+ public static boolean isJavac(DesugarTestConfiguration c) {
+ return c == JAVAC;
+ }
+
+ public static boolean isNotJavac(DesugarTestConfiguration c) {
+ return c != JAVAC;
+ }
+
+ public static boolean isNotDesugared(DesugarTestConfiguration c) {
+ return isJavac(c);
+ }
+
+ public static boolean isDesugared(DesugarTestConfiguration c) {
+ return isNotJavac(c);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/DesugarTestRunResult.java b/src/test/java/com/android/tools/r8/DesugarTestRunResult.java
new file mode 100644
index 0000000..4bffdfa
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/DesugarTestRunResult.java
@@ -0,0 +1,26 @@
+// Copyright (c) 2020, 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;
+
+import com.android.tools.r8.utils.Pair;
+import java.util.List;
+
+public class DesugarTestRunResult
+ extends TestRunResultCollection<DesugarTestConfiguration, DesugarTestRunResult> {
+
+ public static DesugarTestRunResult create(
+ List<Pair<DesugarTestConfiguration, TestRunResult<?>>> runs) {
+ assert !runs.isEmpty();
+ return new DesugarTestRunResult(runs);
+ }
+
+ private DesugarTestRunResult(List<Pair<DesugarTestConfiguration, TestRunResult<?>>> runs) {
+ super(runs);
+ }
+
+ @Override
+ DesugarTestRunResult self() {
+ return this;
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/NeverMerge.java b/src/test/java/com/android/tools/r8/NoHorizontalClassMerging.java
similarity index 71%
copy from src/test/java/com/android/tools/r8/NeverMerge.java
copy to src/test/java/com/android/tools/r8/NoHorizontalClassMerging.java
index 7c6922a..8e45d4a 100644
--- a/src/test/java/com/android/tools/r8/NeverMerge.java
+++ b/src/test/java/com/android/tools/r8/NoHorizontalClassMerging.java
@@ -1,10 +1,11 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2020, 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;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
-public @interface NeverMerge {}
+public @interface NoHorizontalClassMerging {}
diff --git a/src/test/java/com/android/tools/r8/NeverMerge.java b/src/test/java/com/android/tools/r8/NoStaticClassMerging.java
similarity index 72%
copy from src/test/java/com/android/tools/r8/NeverMerge.java
copy to src/test/java/com/android/tools/r8/NoStaticClassMerging.java
index 7c6922a..b97416f 100644
--- a/src/test/java/com/android/tools/r8/NeverMerge.java
+++ b/src/test/java/com/android/tools/r8/NoStaticClassMerging.java
@@ -1,10 +1,11 @@
-// Copyright (c) 2018, the R8 project authors. Please see the AUTHORS file
+// Copyright (c) 2020, 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;
import java.lang.annotation.ElementType;
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
-public @interface NeverMerge {}
+public @interface NoStaticClassMerging {}
diff --git a/src/test/java/com/android/tools/r8/NeverMerge.java b/src/test/java/com/android/tools/r8/NoVerticalClassMerging.java
similarity index 88%
rename from src/test/java/com/android/tools/r8/NeverMerge.java
rename to src/test/java/com/android/tools/r8/NoVerticalClassMerging.java
index 7c6922a..33d15ce 100644
--- a/src/test/java/com/android/tools/r8/NeverMerge.java
+++ b/src/test/java/com/android/tools/r8/NoVerticalClassMerging.java
@@ -7,4 +7,4 @@
import java.lang.annotation.Target;
@Target({ElementType.TYPE})
-public @interface NeverMerge {}
+public @interface NoVerticalClassMerging {}
diff --git a/src/test/java/com/android/tools/r8/R8TestBuilder.java b/src/test/java/com/android/tools/r8/R8TestBuilder.java
index 3c8a16b..85705d2 100644
--- a/src/test/java/com/android/tools/r8/R8TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/R8TestBuilder.java
@@ -4,6 +4,7 @@
package com.android.tools.r8;
import static com.android.tools.r8.dexsplitter.SplitterTestBase.simpleSplitProvider;
+import static com.android.tools.r8.dexsplitter.SplitterTestBase.splitWithNonJavaFile;
import static org.hamcrest.CoreMatchers.containsString;
import com.android.tools.r8.R8Command.Builder;
@@ -15,12 +16,16 @@
import com.android.tools.r8.experimental.graphinfo.GraphConsumer;
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.shaking.CollectingGraphConsumer;
+import com.android.tools.r8.shaking.NoHorizontalClassMergingRule;
+import com.android.tools.r8.shaking.NoStaticClassMergingRule;
+import com.android.tools.r8.shaking.NoVerticalClassMergingRule;
import com.android.tools.r8.shaking.ProguardConfiguration;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
+import com.android.tools.r8.utils.Pair;
import java.io.IOException;
import java.nio.file.Path;
import java.util.ArrayList;
@@ -55,7 +60,9 @@
private boolean enableConstantArgumentAnnotations = false;
private boolean enableInliningAnnotations = false;
private boolean enableMemberValuePropagationAnnotations = false;
- private boolean enableMergeAnnotations = false;
+ private boolean enableNoVerticalClassMergingAnnotations = false;
+ private boolean enableNoHorizontalClassMergingAnnotations = false;
+ private boolean enableNoStaticClassMergingAnnotations = false;
private boolean enableNeverClassInliningAnnotations = false;
private boolean enableNeverReprocessClassInitializerAnnotations = false;
private boolean enableNeverReprocessMethodAnnotations = false;
@@ -76,7 +83,9 @@
if (enableConstantArgumentAnnotations
|| enableInliningAnnotations
|| enableMemberValuePropagationAnnotations
- || enableMergeAnnotations
+ || enableNoVerticalClassMergingAnnotations
+ || enableNoHorizontalClassMergingAnnotations
+ || enableNoStaticClassMergingAnnotations
|| enableNeverClassInliningAnnotations
|| enableNeverReprocessClassInitializerAnnotations
|| enableNeverReprocessMethodAnnotations
@@ -406,10 +415,38 @@
return self();
}
- public T enableMergeAnnotations() {
- if (!enableMergeAnnotations) {
- enableMergeAnnotations = true;
- addInternalKeepRules("-nevermerge @com.android.tools.r8.NeverMerge class *");
+ private void addInternalMatchInterfaceRule(String name, Class matchInterface) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("-");
+ sb.append(name);
+ sb.append(" @");
+ sb.append(matchInterface.getTypeName());
+ sb.append(" class *");
+ addInternalKeepRules(sb.toString());
+ }
+
+ public T enableNoVerticalClassMergingAnnotations() {
+ if (!enableNoVerticalClassMergingAnnotations) {
+ enableNoVerticalClassMergingAnnotations = true;
+ addInternalMatchInterfaceRule(
+ NoVerticalClassMergingRule.RULE_NAME, NoVerticalClassMerging.class);
+ }
+ return self();
+ }
+
+ public T enableNoHorizontalClassMergingAnnotations() {
+ if (!enableNoHorizontalClassMergingAnnotations) {
+ enableNoHorizontalClassMergingAnnotations = true;
+ addInternalMatchInterfaceRule(
+ NoHorizontalClassMergingRule.RULE_NAME, NoHorizontalClassMerging.class);
+ }
+ return self();
+ }
+
+ public T enableNoStaticClassMergingAnnotations() {
+ if (!enableNoStaticClassMergingAnnotations) {
+ enableNoStaticClassMergingAnnotations = true;
+ addInternalMatchInterfaceRule(NoStaticClassMergingRule.RULE_NAME, NoStaticClassMerging.class);
}
return self();
}
@@ -593,4 +630,14 @@
features.add(path);
return self();
}
+
+ public T addFeatureSplitWithResources(
+ Collection<Pair<String, String>> nonJavaFiles, Class<?>... classes) throws IOException {
+ Path path = getState().getNewTempFolder().resolve("feature.zip");
+ builder.addFeatureSplit(
+ builder ->
+ splitWithNonJavaFile(builder, path, getState().getTempFolder(), nonJavaFiles, classes));
+ features.add(path);
+ return self();
+ }
}
diff --git a/src/test/java/com/android/tools/r8/R8TestCompileResult.java b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
index 3fa1091..c2a1dac 100644
--- a/src/test/java/com/android/tools/r8/R8TestCompileResult.java
+++ b/src/test/java/com/android/tools/r8/R8TestCompileResult.java
@@ -71,6 +71,10 @@
return features.get(index);
}
+ public List<Path> getFeatures() {
+ return features;
+ }
+
@Override
public String getStdout() {
return state.getStdout();
@@ -132,6 +136,10 @@
return new R8TestRunResult(app, runtime, result, proguardMap, this::graphInspector);
}
+ public R8TestCompileResult addFeatureSplitsToRunClasspathFiles() {
+ return addRunClasspathFiles(features);
+ }
+
public R8TestRunResult runFeature(TestRuntime runtime, Class<?> mainFeatureClass)
throws IOException {
return runFeature(runtime, mainFeatureClass, features.get(0));
diff --git a/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java b/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
deleted file mode 100644
index a022ecf..0000000
--- a/src/test/java/com/android/tools/r8/R8UnreachableCodeTest.java
+++ /dev/null
@@ -1,55 +0,0 @@
-// Copyright (c) 2016, 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;
-
-import static org.junit.Assert.assertEquals;
-
-import com.android.tools.r8.dex.ApplicationReader;
-import com.android.tools.r8.graph.AppView;
-import com.android.tools.r8.graph.DexEncodedMethod;
-import com.android.tools.r8.graph.DexProgramClass;
-import com.android.tools.r8.graph.DirectMappedDexApplication;
-import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.utils.AndroidApp;
-import com.android.tools.r8.utils.InternalOptions;
-import com.android.tools.r8.utils.Timing;
-import java.io.IOException;
-import java.nio.file.Path;
-import java.nio.file.Paths;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-import org.junit.Ignore;
-import org.junit.Test;
-
-public class R8UnreachableCodeTest {
-
- private static final Path SMALI_DIR = Paths.get(ToolHelper.SMALI_BUILD_DIR);
-
- @Ignore
- @Test
- public void UnreachableCode() throws IOException, ExecutionException {
- String name = "unreachable-code-1";
- AndroidApp input =
- AndroidApp.builder()
- .addProgramFiles(SMALI_DIR.resolve(name).resolve(name + ".dex"))
- .build();
- ExecutorService executorService = Executors.newSingleThreadExecutor();
- Timing timing = Timing.empty();
- InternalOptions options = new InternalOptions();
- options.programConsumer = DexIndexedConsumer.emptyConsumer();
- DirectMappedDexApplication application =
- new ApplicationReader(input, options, timing).read(executorService).toDirect();
- IRConverter converter = new IRConverter(AppView.createForR8(application), null);
- converter.optimize();
- DexProgramClass clazz = application.classes().iterator().next();
- assertEquals(4, clazz.getMethodCollection().numberOfDirectMethods());
- for (DexEncodedMethod method : clazz.directMethods()) {
- if (!method.method.name.toString().equals("main")) {
- assertEquals(2, method.getCode().asDexCode().instructions.length);
- }
- }
- }
-}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 342920c..d065497 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -20,6 +20,7 @@
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.dex.ApplicationReader;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.features.ClassToFeatureSplitMap;
import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.AppInfoWithClassHierarchy;
import com.android.tools.r8.graph.AppServices;
@@ -45,6 +46,8 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.EnqueuerFactory;
import com.android.tools.r8.shaking.MainDexClasses;
+import com.android.tools.r8.shaking.NoStaticClassMergingRule;
+import com.android.tools.r8.shaking.NoVerticalClassMergingRule;
import com.android.tools.r8.shaking.ProguardClassFilter;
import com.android.tools.r8.shaking.ProguardClassNameList;
import com.android.tools.r8.shaking.ProguardConfiguration;
@@ -76,6 +79,7 @@
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import com.google.common.base.Predicates;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.collect.ImmutableList;
@@ -105,6 +109,7 @@
import java.util.function.BiFunction;
import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.Predicate;
import java.util.jar.JarOutputStream;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -220,46 +225,78 @@
return testForRuntime(parameters.getRuntime(), parameters.getApiLevel());
}
- public TestBuilder<? extends TestRunResult<?>, ?> testForDesugaring(TestParameters parameters) {
+ public TestBuilder<DesugarTestRunResult, ?> testForDesugaring(TestParameters parameters) {
return testForDesugaring(
- parameters.getRuntime().getBackend(), parameters.getApiLevel(), o -> {});
+ parameters.getRuntime().getBackend(),
+ parameters.getApiLevel(),
+ o -> {},
+ Predicates.alwaysTrue());
}
- public TestBuilder<? extends TestRunResult<?>, ?> testForDesugaring(
+ public TestBuilder<DesugarTestRunResult, ?> testForDesugaring(
TestParameters parameters, Consumer<InternalOptions> optionsModification) {
return testForDesugaring(
- parameters.getRuntime().getBackend(), parameters.getApiLevel(), optionsModification);
+ parameters.getRuntime().getBackend(),
+ parameters.getApiLevel(),
+ optionsModification,
+ Predicates.alwaysTrue());
}
- private TestBuilder<? extends TestRunResult<?>, ?> testForDesugaring(
- Backend backend, AndroidApiLevel apiLevel, Consumer<InternalOptions> optionsModification) {
+ @Deprecated
+ // This is not supposed to be used for tests. It is here for debugging where filtering to run
+ // only some (typically one) test configuration is helpful.
+ public TestBuilder<DesugarTestRunResult, ?> testForDesugaring(
+ TestParameters parameters,
+ Consumer<InternalOptions> optionsModification,
+ Predicate<DesugarTestConfiguration> filter) {
+ return testForDesugaring(
+ parameters.getRuntime().getBackend(),
+ parameters.getApiLevel(),
+ optionsModification,
+ filter);
+ }
+
+ private TestBuilder<DesugarTestRunResult, ?> testForDesugaring(
+ Backend backend,
+ AndroidApiLevel apiLevel,
+ Consumer<InternalOptions> optionsModification,
+ Predicate<DesugarTestConfiguration> filter) {
assert apiLevel != null : "No API level. Add .withAllApiLevelsAlsoForCf() to test parameters?";
TestState state = new TestState(temp);
- List<Pair<String, TestBuilder<? extends TestRunResult<?>, ?>>> builders;
+ ImmutableList.Builder<
+ Pair<DesugarTestConfiguration, TestBuilder<? extends TestRunResult<?>, ?>>>
+ builders = ImmutableList.builder();
if (backend == Backend.CF) {
- builders =
- ImmutableList.of(
- new Pair<>("JAVAC", JvmTestBuilder.create(state)),
- new Pair<>(
- "D8/CF",
- D8TestBuilder.create(state, Backend.CF)
- .setMinApi(apiLevel)
- .addOptionsModification(optionsModification)));
+ if (filter.test(DesugarTestConfiguration.JAVAC)) {
+ builders.add(new Pair<>(DesugarTestConfiguration.JAVAC, JvmTestBuilder.create(state)));
+ }
+ if (filter.test(DesugarTestConfiguration.D8_CF)) {
+ builders.add(
+ new Pair<>(
+ DesugarTestConfiguration.D8_CF,
+ D8TestBuilder.create(state, Backend.CF)
+ .setMinApi(apiLevel)
+ .addOptionsModification(optionsModification)));
+ }
} else {
assert backend == Backend.DEX;
- builders =
- ImmutableList.of(
- new Pair<>(
- "D8/DEX",
- D8TestBuilder.create(state, Backend.DEX)
- .setMinApi(apiLevel)
- .addOptionsModification(optionsModification)),
- new Pair<>(
- "D8/DEX o D8/CF",
- IntermediateCfD8TestBuilder.create(state, apiLevel)
- .addOptionsModification(optionsModification)));
+ if (filter.test(DesugarTestConfiguration.D8_DEX)) {
+ builders.add(
+ new Pair<>(
+ DesugarTestConfiguration.D8_DEX,
+ D8TestBuilder.create(state, Backend.DEX)
+ .setMinApi(apiLevel)
+ .addOptionsModification(optionsModification)));
+ }
+ if (filter.test(DesugarTestConfiguration.D8_CF_D8_DEX)) {
+ builders.add(
+ new Pair<>(
+ DesugarTestConfiguration.D8_CF_D8_DEX,
+ IntermediateCfD8TestBuilder.create(state, apiLevel)
+ .addOptionsModification(optionsModification)));
+ }
}
- return TestBuilderCollection.create(state, builders);
+ return DesugarTestBuilder.create(state, builders.build());
}
public ProguardTestBuilder testForProguard() {
@@ -652,6 +689,7 @@
throws Exception {
return AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
readApplicationForDexOutput(app, new InternalOptions()),
+ ClassToFeatureSplitMap.createEmptyClassToFeatureSplitMap(),
MainDexClasses.createEmptyMainDexClasses());
}
@@ -1053,8 +1091,19 @@
+ keepMainProguardConfiguration(clazz);
}
- public static String neverMergeRule() {
- return "-nevermerge @com.android.tools.r8.NeverMerge class *";
+ @Deprecated
+ private static String matchInterfaceRule(String name, Class matchInterface) {
+ return "-" + name + " @" + matchInterface.getTypeName() + " class *";
+ }
+
+ @Deprecated
+ public static String noVerticalClassMergingRule() {
+ return matchInterfaceRule(NoVerticalClassMergingRule.RULE_NAME, NoVerticalClassMerging.class);
+ }
+
+ @Deprecated
+ public static String noStaticClassMergingRule() {
+ return matchInterfaceRule(NoStaticClassMergingRule.RULE_NAME, NoStaticClassMerging.class);
}
/**
diff --git a/src/test/java/com/android/tools/r8/TestBuilder.java b/src/test/java/com/android/tools/r8/TestBuilder.java
index 73a1605..8534d9f 100644
--- a/src/test/java/com/android/tools/r8/TestBuilder.java
+++ b/src/test/java/com/android/tools/r8/TestBuilder.java
@@ -174,7 +174,9 @@
KeepUnusedArguments.class,
NeverClassInline.class,
NeverInline.class,
- NeverMerge.class,
+ NoVerticalClassMerging.class,
+ NoHorizontalClassMerging.class,
+ NoStaticClassMerging.class,
NeverPropagateValue.class);
}
diff --git a/src/test/java/com/android/tools/r8/TestBuilderCollection.java b/src/test/java/com/android/tools/r8/TestBuilderCollection.java
index a537aea..0192832 100644
--- a/src/test/java/com/android/tools/r8/TestBuilderCollection.java
+++ b/src/test/java/com/android/tools/r8/TestBuilderCollection.java
@@ -6,49 +6,28 @@
import com.android.tools.r8.debug.DebugTestConfig;
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.utils.Pair;
-import java.io.IOException;
import java.nio.file.Path;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
-import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
/** Abstraction to allow setup and execution of multiple test builders. */
-public class TestBuilderCollection
- extends TestBuilder<TestRunResultCollection, TestBuilderCollection> {
+public abstract class TestBuilderCollection<
+ C extends Enum<C>,
+ RR extends TestRunResultCollection<C, RR>,
+ T extends TestBuilderCollection<C, RR, T>>
+ extends TestBuilder<RR, T> {
- public static TestBuilderCollection create(
- TestState state,
- List<Pair<String, TestBuilder<? extends TestRunResult<?>, ?>>> testBuilders) {
- return new TestBuilderCollection(state, testBuilders);
- }
+ final List<Pair<C, TestBuilder<? extends TestRunResult<?>, ?>>> builders;
- private final List<Pair<String, TestBuilder<? extends TestRunResult<?>, ?>>> builders;
-
- private TestBuilderCollection(
- TestState state, List<Pair<String, TestBuilder<? extends TestRunResult<?>, ?>>> builders) {
+ TestBuilderCollection(
+ TestState state, List<Pair<C, TestBuilder<? extends TestRunResult<?>, ?>>> builders) {
super(state);
assert !builders.isEmpty();
this.builders = builders;
}
- @Override
- TestBuilderCollection self() {
- return this;
- }
-
- @Override
- public TestRunResultCollection run(TestRuntime runtime, String mainClass, String... args)
- throws CompilationFailedException, ExecutionException, IOException {
- List<Pair<String, TestRunResult<?>>> runs = new ArrayList<>(builders.size());
- for (Pair<String, TestBuilder<? extends TestRunResult<?>, ?>> builder : builders) {
- runs.add(new Pair<>(builder.getFirst(), builder.getSecond().run(runtime, mainClass, args)));
- }
- return TestRunResultCollection.create(runs);
- }
-
- private TestBuilderCollection forEach(Consumer<TestBuilder<? extends TestRunResult<?>, ?>> fn) {
+ private T forEach(Consumer<TestBuilder<? extends TestRunResult<?>, ?>> fn) {
builders.forEach(b -> fn.accept(b.getSecond()));
return self();
}
@@ -59,42 +38,42 @@
}
@Override
- public TestBuilderCollection addProgramFiles(Collection<Path> files) {
+ public T addProgramFiles(Collection<Path> files) {
return forEach(b -> b.addProgramFiles(files));
}
@Override
- public TestBuilderCollection addProgramClassFileData(Collection<byte[]> classes) {
+ public T addProgramClassFileData(Collection<byte[]> classes) {
return forEach(b -> b.addProgramClassFileData(classes));
}
@Override
- public TestBuilderCollection addProgramDexFileData(Collection<byte[]> data) {
+ public T addProgramDexFileData(Collection<byte[]> data) {
return forEach(b -> b.addProgramDexFileData(data));
}
@Override
- public TestBuilderCollection addLibraryFiles(Collection<Path> files) {
+ public T addLibraryFiles(Collection<Path> files) {
return forEach(b -> b.addLibraryFiles(files));
}
@Override
- public TestBuilderCollection addLibraryClasses(Collection<Class<?>> classes) {
+ public T addLibraryClasses(Collection<Class<?>> classes) {
return forEach(b -> b.addLibraryClasses(classes));
}
@Override
- public TestBuilderCollection addClasspathClasses(Collection<Class<?>> classes) {
+ public T addClasspathClasses(Collection<Class<?>> classes) {
return forEach(b -> b.addClasspathClasses(classes));
}
@Override
- public TestBuilderCollection addClasspathFiles(Collection<Path> files) {
+ public T addClasspathFiles(Collection<Path> files) {
return forEach(b -> b.addClasspathFiles(files));
}
@Override
- public TestBuilderCollection addRunClasspathFiles(Collection<Path> files) {
+ public T addRunClasspathFiles(Collection<Path> files) {
return forEach(b -> b.addRunClasspathFiles(files));
}
}
diff --git a/src/test/java/com/android/tools/r8/TestRunResultCollection.java b/src/test/java/com/android/tools/r8/TestRunResultCollection.java
index af4256a..4912ef8 100644
--- a/src/test/java/com/android/tools/r8/TestRunResultCollection.java
+++ b/src/test/java/com/android/tools/r8/TestRunResultCollection.java
@@ -6,70 +6,81 @@
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.ThrowingConsumer;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.base.Predicates;
import com.google.common.base.Strings;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.function.Consumer;
+import java.util.function.Predicate;
import org.hamcrest.Matcher;
/** Checking container for checking the same properties of multiple run results. */
-public class TestRunResultCollection extends TestRunResult<TestRunResultCollection> {
+public abstract class TestRunResultCollection<
+ C extends Enum<C>, RR extends TestRunResultCollection<C, RR>>
+ extends TestRunResult<RR> {
- public static TestRunResultCollection create(List<Pair<String, TestRunResult<?>>> runs) {
- assert !runs.isEmpty();
- return new TestRunResultCollection(runs);
- }
+ private final List<Pair<C, TestRunResult<?>>> runs;
- private final List<Pair<String, TestRunResult<?>>> runs;
-
- public TestRunResultCollection(List<Pair<String, TestRunResult<?>>> runs) {
+ public TestRunResultCollection(List<Pair<C, TestRunResult<?>>> runs) {
this.runs = runs;
}
- @Override
- TestRunResultCollection self() {
- return this;
- }
-
- private TestRunResultCollection forEach(Consumer<TestRunResult<?>> fn) {
+ private RR forEach(Consumer<TestRunResult<?>> fn) {
runs.forEach(r -> fn.accept(r.getSecond()));
return self();
}
@Override
- public TestRunResultCollection assertSuccess() {
+ public RR assertSuccess() {
return forEach(TestRunResult::assertSuccess);
}
@Override
- public TestRunResultCollection assertFailure() {
+ public RR assertFailure() {
return forEach(TestRunResult::assertFailure);
}
@Override
- public TestRunResultCollection assertStdoutMatches(Matcher<String> matcher) {
+ public RR assertStdoutMatches(Matcher<String> matcher) {
return forEach(r -> r.assertStdoutMatches(matcher));
}
@Override
- public TestRunResultCollection assertStderrMatches(Matcher<String> matcher) {
+ public RR assertStderrMatches(Matcher<String> matcher) {
return forEach(r -> r.assertStderrMatches(matcher));
}
@Override
- public <E extends Throwable> TestRunResultCollection inspect(
- ThrowingConsumer<CodeInspector, E> consumer) throws IOException, ExecutionException, E {
- for (Pair<String, TestRunResult<?>> run : runs) {
- run.getSecond().inspect(consumer);
+ public <E extends Throwable> RR inspect(ThrowingConsumer<CodeInspector, E> consumer)
+ throws IOException, ExecutionException, E {
+ return inspectIf(Predicates.alwaysTrue(), consumer);
+ }
+
+ public RR applyIf(Predicate<C> filter, Consumer<TestRunResult<?>> fn) {
+ for (Pair<C, TestRunResult<?>> run : runs) {
+ if (filter.test(run.getFirst())) {
+ fn.accept(run.getSecond());
+ }
+ }
+ return self();
+ }
+
+ public <E extends Throwable> RR inspectIf(
+ Predicate<C> filter, ThrowingConsumer<CodeInspector, E> consumer)
+ throws IOException, ExecutionException, E {
+ for (Pair<C, TestRunResult<?>> run : runs) {
+ if (filter.test(run.getFirst())) {
+ run.getSecond().inspect(consumer);
+ }
}
return self();
}
@Override
- public TestRunResultCollection disassemble() throws IOException, ExecutionException {
- for (Pair<String, TestRunResult<?>> run : runs) {
- String name = run.getFirst();
+ public RR disassemble() throws IOException, ExecutionException {
+ for (Pair<C, TestRunResult<?>> run : runs) {
+ String name = run.getFirst().name();
System.out.println(name + " " + Strings.repeat("=", 80 - name.length() - 1));
run.getSecond().disassemble();
}
diff --git a/src/test/java/com/android/tools/r8/ToolHelper.java b/src/test/java/com/android/tools/r8/ToolHelper.java
index 7de9a9a..e6fd9e0 100644
--- a/src/test/java/com/android/tools/r8/ToolHelper.java
+++ b/src/test/java/com/android/tools/r8/ToolHelper.java
@@ -121,6 +121,9 @@
public static final String JAVA_CLASSES_DIR = BUILD_DIR + "classes/java/";
public static final String JDK_11_TESTS_CLASSES_DIR = JAVA_CLASSES_DIR + "jdk11Tests/";
+ public static final String ASM_JAR = BUILD_DIR + "deps/asm-8.0.jar";
+ public static final String ASM_UTIL_JAR = BUILD_DIR + "deps/asm-util-8.0.jar";
+
public static final Path API_SAMPLE_JAR = Paths.get("tests", "r8_api_usage_sample.jar");
public static final String LINE_SEPARATOR = StringUtils.LINE_SEPARATOR;
diff --git a/src/test/java/com/android/tools/r8/accessrelaxation/NoRelaxationForSerializableTest.java b/src/test/java/com/android/tools/r8/accessrelaxation/NoRelaxationForSerializableTest.java
index 2cb3e95..7521316 100644
--- a/src/test/java/com/android/tools/r8/accessrelaxation/NoRelaxationForSerializableTest.java
+++ b/src/test/java/com/android/tools/r8/accessrelaxation/NoRelaxationForSerializableTest.java
@@ -8,8 +8,8 @@
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -31,7 +31,7 @@
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
-@NeverMerge
+@NoVerticalClassMerging
class MySerializable implements Serializable {
@NeverPropagateValue transient int value;
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/DataAdapter.java b/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/DataAdapter.java
index 5209511..a4d94bb 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/DataAdapter.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/DataAdapter.java
@@ -4,11 +4,11 @@
package com.android.tools.r8.bridgeremoval.bridgestokeep;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
public interface DataAdapter {
- @NeverMerge
+ @NoVerticalClassMerging
interface Observer extends ObservableList.Observer {}
void registerObserver(Observer observer);
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/KeepNonVisibilityBridgeMethodsTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/KeepNonVisibilityBridgeMethodsTest.java
index 3b7481b..0e373e9 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/KeepNonVisibilityBridgeMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/bridgestokeep/KeepNonVisibilityBridgeMethodsTest.java
@@ -54,7 +54,7 @@
.enableNeverClassInliningAnnotations()
// TODO(b/120764902): MemberSubject.getOriginalName() is not working without the @NeverMerge
// annotation on DataAdapter.Observer.
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableProguardTestOptions()
.minification(minification)
.setMinApi(parameters.getApiLevel())
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java
index 410d418..c9f7d21 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/BridgeHoistingAccessibilityTest.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -72,7 +72,7 @@
.transform())
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -113,7 +113,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class B extends BridgeHoistingAccessibilityTestClasses.A {
// This bridge cannot be hoisted to A, since it would then become inaccessible to the call site
@@ -136,7 +136,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class BWithRangedInvoke extends AWithRangedInvoke {
// This bridge cannot be hoisted to A, since it would then become inaccessible to the call site
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/InterfaceBridgeHoistingTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/InterfaceBridgeHoistingTest.java
index 9fdc87f..0e79433 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/InterfaceBridgeHoistingTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/InterfaceBridgeHoistingTest.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -38,7 +38,7 @@
.transform())
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -53,10 +53,10 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/KeptBridgeHoistingTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/KeptBridgeHoistingTest.java
index b4ce765..fc6ac6b 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/KeptBridgeHoistingTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/KeptBridgeHoistingTest.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -43,7 +43,7 @@
.addKeepMainRule(TestClass.class)
.addKeepRules("-keep class " + B.class.getTypeName() + " { java.lang.String bridge(...); }")
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -69,7 +69,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/NonReboundBridgeHoistingTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/NonReboundBridgeHoistingTest.java
index d93514a..02c948c 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/NonReboundBridgeHoistingTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/NonReboundBridgeHoistingTest.java
@@ -43,7 +43,7 @@
transformer(C.class).setBridge(C.class.getDeclaredMethod("bridge")).transform())
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/NonSuperclassBridgeHoistingTest.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/NonSuperclassBridgeHoistingTest.java
index 87310d2..f2a91a8 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/NonSuperclassBridgeHoistingTest.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/NonSuperclassBridgeHoistingTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -43,7 +43,7 @@
.transform())
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -70,7 +70,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {}
@NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/testclasses/BridgeHoistingAccessibilityTestClasses.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/testclasses/BridgeHoistingAccessibilityTestClasses.java
index 55daf92..9990f62 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/testclasses/BridgeHoistingAccessibilityTestClasses.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/testclasses/BridgeHoistingAccessibilityTestClasses.java
@@ -5,13 +5,13 @@
package com.android.tools.r8.bridgeremoval.hoisting.testclasses;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.bridgeremoval.hoisting.BridgeHoistingAccessibilityTest;
import com.android.tools.r8.bridgeremoval.hoisting.BridgeHoistingAccessibilityTest.CWithRangedInvoke;
public class BridgeHoistingAccessibilityTestClasses {
- @NeverMerge
+ @NoVerticalClassMerging
public static class A {
@NeverInline
@@ -28,7 +28,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public static class AWithRangedInvoke {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/testclasses/NonReboundBridgeHoistingTestClasses.java b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/testclasses/NonReboundBridgeHoistingTestClasses.java
index f66c6a3..c419f7f 100644
--- a/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/testclasses/NonReboundBridgeHoistingTestClasses.java
+++ b/src/test/java/com/android/tools/r8/bridgeremoval/hoisting/testclasses/NonReboundBridgeHoistingTestClasses.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.bridgeremoval.hoisting.testclasses;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
public class NonReboundBridgeHoistingTestClasses {
@@ -13,7 +13,7 @@
return A.class;
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@NeverInline
@@ -22,6 +22,6 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public static class B extends A {}
}
diff --git a/src/test/java/com/android/tools/r8/cf/MethodHandleTest.java b/src/test/java/com/android/tools/r8/cf/MethodHandleTest.java
index c0067d6..690dd6b 100644
--- a/src/test/java/com/android/tools/r8/cf/MethodHandleTest.java
+++ b/src/test/java/com/android/tools/r8/cf/MethodHandleTest.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.cf;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
@@ -82,7 +82,7 @@
// Class that is only mentioned in return value of LDC(MethodType)-instruction.
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
int ii = 42;
diff --git a/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java b/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
index 3062ae8..2a6652b 100644
--- a/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
+++ b/src/test/java/com/android/tools/r8/cf/MethodHandleTestRunner.java
@@ -177,7 +177,7 @@
builder.addProguardConfiguration(
Arrays.asList(
keepMainProguardConfiguration(MethodHandleTest.class),
- neverMergeRule(),
+ noVerticalClassMergingRule(),
// Prevent the second argument of C.svic(), C.sjic(), I.sjic() and I.svic() from
// being removed although they are never used unused. This is needed since these
// methods are accessed reflectively.
diff --git a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedOverriddenMethodTest.java b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedOverriddenMethodTest.java
index 3f5b778..e2defd2 100644
--- a/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedOverriddenMethodTest.java
+++ b/src/test/java/com/android/tools/r8/checkdiscarded/CheckDiscardedOverriddenMethodTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
@@ -48,7 +48,7 @@
"-checkdiscard class **.*$" + targetClass.getSimpleName() + " { void gone(); }")
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.minification(minification)
.setMinApi(parameters.getRuntime())
// Asserting that -checkdiscard is not giving any information out on an un-removed
@@ -70,7 +70,7 @@
test(TestMain2.class, Itf.class);
}
- @NeverMerge
+ @NoVerticalClassMerging
static class Base {
@NeverInline
void gone() {
@@ -93,7 +93,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface Itf {
void gone();
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java
index edd84cb..5eb49b1 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistinguishedByIndirectCheckCastToInterfaceTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestParameters;
import org.junit.Test;
@@ -27,7 +27,7 @@
.addKeepMainRule(Main.class)
.addOptionsModification(
options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
@@ -41,7 +41,7 @@
});
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
public interface I {
void bar();
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java
index c6f58af..70e7c0d 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ClassesDistuingishedByIndirectInstanceOfInterfaceCheckCast.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestParameters;
import org.junit.Test;
@@ -28,7 +28,7 @@
.addOptionsModification(
options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
@@ -42,7 +42,7 @@
}
@NeverClassInline
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void bar();
}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/InnerOuterClassesTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/InnerOuterClassesTest.java
new file mode 100644
index 0000000..075448a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/InnerOuterClassesTest.java
@@ -0,0 +1,76 @@
+// Copyright (c) 2020, 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.classmerging.horizontal;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.TestParameters;
+import org.junit.Test;
+
+public class InnerOuterClassesTest extends HorizontalClassMergingTestBase {
+ public InnerOuterClassesTest(TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .enableNeverClassInliningAnnotations()
+ .addKeepAttributes("InnerClasses", "EnclosingMethod")
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("a", "b", "c", "d")
+ .inspect(
+ codeInspector -> {
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(codeInspector.clazz(A.B.class), isPresent());
+ assertThat(codeInspector.clazz(C.class), isPresent());
+ assertThat(codeInspector.clazz(A.D.class), isPresent());
+ });
+ }
+
+ @NeverClassInline
+ public static class A {
+ public A() {
+ System.out.println("a");
+ }
+
+ @NeverClassInline
+ public static class B {
+ public B() {
+ System.out.println("b");
+ }
+ }
+
+ @NeverClassInline
+ public static class D {
+ public D() {
+ System.out.println("d");
+ }
+ }
+ }
+
+ @NeverClassInline
+ public static class C {
+ public C() {
+ System.out.println("c");
+ }
+ }
+
+ public static class Main {
+ public static void main(String[] args) {
+ A a = new A();
+ A.B b = new A.B();
+ C c = new C();
+ A.D d = new A.D();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
index 1f0daeb..fc4f076 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
@@ -10,7 +10,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestRuntime.CfRuntime;
import com.android.tools.r8.naming.retrace.StackTrace;
@@ -47,7 +47,7 @@
.addKeepAttributeSourceFile()
.addOptionsModification(
options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -77,7 +77,7 @@
});
}
- @NeverMerge
+ @NoVerticalClassMerging
static class Parent {
Parent() {
if (System.currentTimeMillis() >= 0) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAnnotationsTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAnnotationsTest.java
new file mode 100644
index 0000000..b7fc7a1
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoAnnotationsTest.java
@@ -0,0 +1,91 @@
+// Copyright (c) 2020, 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.classmerging.horizontal;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.shaking.ProguardKeepAttributes;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.Test;
+
+public class NoAnnotationsTest extends HorizontalClassMergingTestBase {
+ public NoAnnotationsTest(TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepClassRules(TypeAnnotation.class, MethodAnnotation.class)
+ .addKeepAttributes(ProguardKeepAttributes.RUNTIME_VISIBLE_ANNOTATIONS)
+ .addOptionsModification(
+ options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .enableNeverClassInliningAnnotations()
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("a", "b", "c", "foo")
+ .inspect(
+ codeInspector -> {
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(codeInspector.clazz(B.class), isPresent());
+ assertThat(codeInspector.clazz(C.class), isPresent());
+ });
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.TYPE})
+ public @interface TypeAnnotation {}
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.METHOD})
+ public @interface MethodAnnotation {}
+
+ @NeverClassInline
+ public static class A {
+ public A() {
+ System.out.println("a");
+ }
+ }
+
+ @TypeAnnotation
+ @NeverClassInline
+ public static class B {
+ public B(String v) {
+ System.out.println(v);
+ }
+ }
+
+ @NeverClassInline
+ public static class C {
+ public C(String v) {
+ System.out.println(v);
+ }
+
+ @NeverInline
+ @MethodAnnotation
+ public void foo() {
+ System.out.println("foo");
+ }
+ }
+
+ static class Main {
+ public static void main(String[] args) {
+ A a = new A();
+ B b = new B("b");
+ C c = new C("c");
+ c.foo();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/NoHorizontalClassMergingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoHorizontalClassMergingTest.java
new file mode 100644
index 0000000..dc513c3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/NoHorizontalClassMergingTest.java
@@ -0,0 +1,66 @@
+// Copyright (c) 2020, 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.classmerging.horizontal;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NoHorizontalClassMerging;
+import com.android.tools.r8.TestParameters;
+import org.junit.Test;
+
+public class NoHorizontalClassMergingTest extends HorizontalClassMergingTestBase {
+ public NoHorizontalClassMergingTest(
+ TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .enableNoHorizontalClassMergingAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("a", "b")
+ .inspect(
+ codeInspector -> {
+ if (enableHorizontalClassMerging) {
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(codeInspector.clazz(B.class), isPresent());
+ } else {
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(codeInspector.clazz(B.class), isPresent());
+ }
+ });
+ }
+
+ @NeverClassInline
+ public static class A {
+ public A() {
+ System.out.println("a");
+ }
+ }
+
+ @NeverClassInline
+ @NoHorizontalClassMerging
+ public static class B {
+ public B(String v) {
+ System.out.println(v);
+ }
+ }
+
+ public static class Main {
+ public static void main(String[] args) {
+ A a = new A();
+ B b = new B("b");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java
new file mode 100644
index 0000000..a1b0951
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMemberAccessTest.java
@@ -0,0 +1,74 @@
+// Copyright (c) 2020, 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.classmerging.horizontal;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.IsNot.not;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.classmerging.horizontal.testclasses.A;
+import com.android.tools.r8.classmerging.horizontal.testclasses.B;
+import org.junit.Test;
+
+public class PackagePrivateMemberAccessTest extends HorizontalClassMergingTestBase {
+ public PackagePrivateMemberAccessTest(
+ TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addProgramClasses(A.class)
+ .addProgramClasses(B.class)
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .allowAccessModification(false)
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("foo", "B", "bar", "5", "foobar")
+ .inspect(
+ codeInspector -> {
+ if (enableHorizontalClassMerging) {
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(codeInspector.clazz(B.class), not(isPresent()));
+ assertThat(codeInspector.clazz(C.class), isPresent());
+ // TODO(b/165517236): Explicitly check classes have been merged.
+ } else {
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(codeInspector.clazz(B.class), isPresent());
+ assertThat(codeInspector.clazz(C.class), isPresent());
+ }
+ });
+ }
+
+ @NeverClassInline
+ public static class C {
+ public C(int v) {
+ System.out.println(v);
+ }
+
+ public void foobar() {
+ System.out.println("foobar");
+ }
+ }
+
+ public static class Main {
+ public static void main(String[] args) {
+ A a = new A();
+ a.foo();
+ B b = a.get("B");
+ b.bar();
+ C c = new C(5);
+ c.foobar();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java
new file mode 100644
index 0000000..cdaeee7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PackagePrivateMembersAccessedTest.java
@@ -0,0 +1,66 @@
+// Copyright (c) 2020, 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.classmerging.horizontal;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.classmerging.horizontal.testclasses.C;
+import com.android.tools.r8.classmerging.horizontal.testclasses.D;
+import org.junit.Test;
+
+public class PackagePrivateMembersAccessedTest extends HorizontalClassMergingTestBase {
+ public PackagePrivateMembersAccessedTest(
+ TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addProgramClasses(C.class)
+ .addProgramClasses(D.class)
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .allowAccessModification(false)
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("foo", "hello", "5", "foobar")
+ .inspect(
+ codeInspector -> {
+ assertThat(codeInspector.clazz(C.class), isPresent());
+ assertThat(codeInspector.clazz(D.class), isPresent());
+ assertThat(codeInspector.clazz(E.class), isPresent());
+ });
+ }
+
+ @NeverClassInline
+ public static class E {
+ public E(int v) {
+ System.out.println(v);
+ }
+
+ public void foobar() {
+ System.out.println("foobar");
+ }
+ }
+
+ public static class Main {
+ public static void main(String[] args) {
+ D d = new D("foo");
+ C c = d.getC("hello");
+ c.bar();
+ E e = new E(5);
+ e.foobar();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberTest.java
new file mode 100644
index 0000000..444d573
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassMemberTest.java
@@ -0,0 +1,65 @@
+// Copyright (c) 2020, 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.classmerging.horizontal;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.TestParameters;
+import org.junit.Test;
+
+public class PinnedClassMemberTest extends HorizontalClassMergingTestBase {
+ public PinnedClassMemberTest(TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepRules("-keepclassmembers class " + B.class.getTypeName() + " { void foo(); }")
+ .addOptionsModification(
+ options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("a", "b", "foo", "true")
+ .inspect(
+ codeInspector -> {
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(codeInspector.clazz(B.class), isPresent());
+ });
+ }
+
+ @NeverClassInline
+ public static class A {
+ public A() {
+ System.out.println("a");
+ }
+ }
+
+ @NeverClassInline
+ public static class B {
+ public B(String s) {
+ System.out.println(s);
+ }
+
+ public void foo() {
+ System.out.println("foo");
+ }
+ }
+
+ public static class Main {
+ public static void main(String[] args) throws Exception {
+ A a = new A();
+ B b = new B("b");
+ b.foo();
+
+ System.out.println(b.getClass().getMethod("foo").getName().equals("foo"));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassTest.java
new file mode 100644
index 0000000..a2b36f3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/PinnedClassTest.java
@@ -0,0 +1,61 @@
+// Copyright (c) 2020, 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.classmerging.horizontal;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.TestParameters;
+import org.junit.Test;
+
+public class PinnedClassTest extends HorizontalClassMergingTestBase {
+ public PinnedClassTest(TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepClassRules(B.class)
+ .addOptionsModification(
+ options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("a", "b", "true", "true")
+ .inspect(
+ codeInspector -> {
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(codeInspector.clazz(B.class), isPresent());
+ });
+ }
+
+ @NeverClassInline
+ public static class A {
+ public A() {
+ System.out.println("a");
+ }
+ }
+
+ @NeverClassInline
+ public static class B {
+ public B(String s) {
+ System.out.println(s);
+ }
+ }
+
+ public static class Main {
+ public static void main(String[] args) {
+ A a = new A();
+ B b = new B("b");
+
+ System.out.println(b.getClass().getSimpleName().equals("PinnedClassTest$B"));
+ System.out.println(!a.getClass().getSimpleName().equals("PinnedClassTest$B"));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/ReferencedInAnnotationTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/ReferencedInAnnotationTest.java
new file mode 100644
index 0000000..620f948
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/ReferencedInAnnotationTest.java
@@ -0,0 +1,111 @@
+// Copyright (c) 2020, 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.classmerging.horizontal;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static com.android.tools.r8.utils.codeinspector.Matchers.notIf;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.graph.DexEncodedAnnotation;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.utils.codeinspector.AnnotationSubject;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import org.junit.Test;
+
+public class ReferencedInAnnotationTest extends HorizontalClassMergingTestBase {
+
+ public ReferencedInAnnotationTest(
+ TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .addKeepClassAndMembersRules(Annotation.class)
+ .addOptionsModification(
+ options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .addKeepRuntimeVisibleAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!")
+ .inspect(this::inspect);
+ }
+
+ private void inspect(CodeInspector inspector) {
+ // TestClass and A should still be present.
+ ClassSubject testClassSubject = inspector.clazz(TestClass.class);
+ assertThat(testClassSubject, isPresent());
+
+ ClassSubject aClassSubject = inspector.clazz(A.class);
+ assertThat(aClassSubject, isPresent());
+
+ // B should have been merged into A if horizontal class merging is enabled.
+ ClassSubject bClassSubject = inspector.clazz(B.class);
+ assertThat(bClassSubject, notIf(isPresent(), enableHorizontalClassMerging));
+
+ // The annotation on TestClass should now refer to A instead of B.
+ AnnotationSubject annotationSubject =
+ testClassSubject.annotation(Annotation.class.getTypeName());
+ assertThat(annotationSubject, isPresent());
+
+ DexEncodedAnnotation encodedAnnotation = annotationSubject.getAnnotation();
+ assertEquals(1, encodedAnnotation.getNumberOfElements());
+
+ DexValue annotationElementValue = encodedAnnotation.getElement(0).getValue();
+ assertTrue(annotationElementValue.isDexValueType());
+
+ DexType annotationElementValueType = annotationElementValue.asDexValueType().getValue();
+ assertEquals(
+ (enableHorizontalClassMerging ? aClassSubject : bClassSubject)
+ .getDexProgramClass()
+ .getType(),
+ annotationElementValueType);
+ }
+
+ @Annotation(B.class)
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ new A();
+ new B("");
+ }
+ }
+
+ @Retention(RetentionPolicy.RUNTIME)
+ @Target({ElementType.TYPE})
+ @interface Annotation {
+ Class<?> value();
+ }
+
+ @NeverClassInline
+ public static class A {
+
+ public A() {
+ System.out.print("Hello");
+ }
+ }
+
+ @NeverClassInline
+ public static class B {
+
+ public B(String s) {
+ System.out.println(" world!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodSuperMerged.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodSuperMerged.java
index f323ec7..19c458f 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodSuperMerged.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodSuperMerged.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestParameters;
import org.junit.Test;
@@ -28,7 +28,7 @@
options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines("foo", "parent b", "parent b", "x", "parent b")
@@ -57,7 +57,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
public static class ParentB {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/A.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/A.java
new file mode 100644
index 0000000..ea0e1c9
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/A.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2020, 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.classmerging.horizontal.testclasses;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+
+@NeverClassInline
+public class A {
+ public void foo() {
+ System.out.println("foo");
+ }
+
+ @NeverInline
+ public B get(String s) {
+ return new B(s);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/B.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/B.java
new file mode 100644
index 0000000..6157508
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/B.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2020, 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.classmerging.horizontal.testclasses;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+
+@NeverClassInline
+public class B {
+ protected B(String a) {
+ System.out.println(a);
+ }
+
+ @NeverInline
+ public void bar() {
+ System.out.println("bar");
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/C.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/C.java
new file mode 100644
index 0000000..f2220c0
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/C.java
@@ -0,0 +1,22 @@
+// Copyright (c) 2020, 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.classmerging.horizontal.testclasses;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+
+@NeverClassInline
+public class C {
+ String field;
+
+ protected C(String field) {
+ this.field = field;
+ }
+
+ @NeverInline
+ public void bar() {
+ System.out.println(field);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/D.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/D.java
new file mode 100644
index 0000000..3348d96
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/testclasses/D.java
@@ -0,0 +1,20 @@
+// Copyright (c) 2020, 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.classmerging.horizontal.testclasses;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+
+@NeverClassInline
+public class D {
+ public D(String v) {
+ System.out.println(v);
+ }
+
+ @NeverInline
+ public C getC(String v) {
+ return new C(v);
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/HorizontalClassMergerSynchronizedMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/HorizontalClassMergerSynchronizedMethodTest.java
index 8ddfef4..5f4945e 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/HorizontalClassMergerSynchronizedMethodTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontalstatic/HorizontalClassMergerSynchronizedMethodTest.java
@@ -8,7 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -53,7 +53,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(HorizontalClassMergerSynchronizedMethodTest.class)
.addKeepMainRule(Main.class)
- .enableMergeAnnotations()
+ .enableNoStaticClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.run(parameters.getRuntime(), Main.class)
@@ -83,7 +83,7 @@
}
}
- @NeverMerge
+ @NoStaticClassMerging
public static class LockThree {
static synchronized void acquire(I c) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithMultiPackageAccessesTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithMultiPackageAccessesTest.java
index a96f8d3..d830cdb 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithMultiPackageAccessesTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/ForceInlineConstructorWithMultiPackageAccessesTest.java
@@ -37,7 +37,7 @@
.addInnerClasses(ForceInlineConstructorWithMultiPackageAccessesTest.class)
.addInnerClasses(ForceInlineConstructorWithMultiPackageAccessesTestClasses.class)
.addKeepMainRule(TestClass.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerSuperCallInStaticTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerSuperCallInStaticTest.java
index 9de435b..90ec4c3 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerSuperCallInStaticTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerSuperCallInStaticTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -57,7 +57,7 @@
.addKeepMainRule(Main.class)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines(EXPECTED)
@@ -82,7 +82,7 @@
.transform();
}
- @NeverMerge
+ @NoVerticalClassMerging
public static class Base {
public void collect() {
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerSynchronizedMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerSynchronizedMethodTest.java
index deff6a8..ff081a4 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerSynchronizedMethodTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/VerticalClassMergerSynchronizedMethodTest.java
@@ -8,7 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -53,7 +53,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(VerticalClassMergerSynchronizedMethodTest.class)
.addKeepMainRule(Main.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutput("Hello World!")
@@ -73,7 +73,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public static class LockTwo extends LockOne {
static synchronized void acquire(I c) {
@@ -83,7 +83,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public static class LockThree {
static synchronized void acquire(I c) {
diff --git a/src/test/java/com/android/tools/r8/classmerging/vertical/testclasses/ForceInlineConstructorWithMultiPackageAccessesTestClasses.java b/src/test/java/com/android/tools/r8/classmerging/vertical/testclasses/ForceInlineConstructorWithMultiPackageAccessesTestClasses.java
index 2b3967a..077c5e3 100644
--- a/src/test/java/com/android/tools/r8/classmerging/vertical/testclasses/ForceInlineConstructorWithMultiPackageAccessesTestClasses.java
+++ b/src/test/java/com/android/tools/r8/classmerging/vertical/testclasses/ForceInlineConstructorWithMultiPackageAccessesTestClasses.java
@@ -4,11 +4,11 @@
package com.android.tools.r8.classmerging.vertical.testclasses;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
public class ForceInlineConstructorWithMultiPackageAccessesTestClasses {
- @NeverMerge
+ @NoVerticalClassMerging
public static class A {
protected A() {}
diff --git a/src/test/java/com/android/tools/r8/desugar/DefaultInterfaceWithIdentifierNameString.java b/src/test/java/com/android/tools/r8/desugar/DefaultInterfaceWithIdentifierNameString.java
index 9eb054c..9c006cb 100644
--- a/src/test/java/com/android/tools/r8/desugar/DefaultInterfaceWithIdentifierNameString.java
+++ b/src/test/java/com/android/tools/r8/desugar/DefaultInterfaceWithIdentifierNameString.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -70,7 +70,7 @@
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.compile()
.inspect(this::inspect)
@@ -86,7 +86,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
@NeverInline
static I newInstance() throws Exception {
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarLambdaWithAnonymousClass.java b/src/test/java/com/android/tools/r8/desugar/DesugarLambdaWithAnonymousClass.java
index 7192449..b2d5b54 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarLambdaWithAnonymousClass.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarLambdaWithAnonymousClass.java
@@ -5,22 +5,22 @@
package com.android.tools.r8.desugar;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.D8TestRunResult;
+import com.android.tools.r8.DesugarTestConfiguration;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import java.nio.file.Path;
+import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
+import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -29,6 +29,14 @@
@RunWith(Parameterized.class)
public class DesugarLambdaWithAnonymousClass extends TestBase {
+ private List<String> EXPECTED_JAVAC_RESULT =
+ ImmutableList.of("Hello from inside lambda$test$0", "Hello from inside lambda$testStatic$1");
+
+ private List<String> EXPECTED_DESUGARED_RESULT =
+ ImmutableList.of(
+ "Hello from inside lambda$test$0$DesugarLambdaWithAnonymousClass$TestClass",
+ "Hello from inside lambda$testStatic$1");
+
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
@@ -73,111 +81,55 @@
assertEquals(2, counter.getCount());
}
- // TODO(158752316): There should be no use of this check.
- private void checkEnclosingMethodWrong(CodeInspector inspector) {
- Counter counter = new Counter();
- inspector.forAllClasses(
- clazz -> {
- if (clazz.getFinalName().endsWith("$TestClass$1")
- || clazz.getFinalName().endsWith("$TestClass$2")) {
- counter.increment();
- assertTrue(clazz.isAnonymousClass());
- DexMethod enclosingMethod = clazz.getFinalEnclosingMethod();
- ClassSubject testClassSubject =
- inspector.clazz(DesugarLambdaWithAnonymousClass.TestClass.class);
- assertEquals(
- testClassSubject, inspector.clazz(enclosingMethod.holder.toSourceString()));
- if (enclosingMethod.name.toString().contains("Static")) {
- assertThat(
- testClassSubject.uniqueMethodWithName(enclosingMethod.name.toString()),
- isPresent());
- } else {
- assertThat(
- testClassSubject.uniqueMethodWithName(enclosingMethod.name.toString()),
- not(isPresent()));
- }
- }
- });
- assertEquals(2, counter.getCount());
- }
-
- private void checkArtResult(D8TestRunResult result) {
- // TODO(158752316): This should neither return null nor fail.
- if (parameters.getRuntime().asDex().getVm().getVersion().isOlderThanOrEqual(Version.V4_4_4)
- || parameters.getRuntime().asDex().getVm().getVersion().isNewerThan(Version.V6_0_1)) {
- result.assertSuccessWithOutputLines(
- "Hello from inside <null>", "Hello from inside lambda$testStatic$1");
- } else {
- result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
- }
- }
-
@BeforeClass
public static void checkExpectedJavacNames() throws Exception {
CodeInspector inspector =
new CodeInspector(
- ToolHelper.getClassFilesForInnerClasses(DesugarLambdaWithLocalClass.class));
- String outer = DesugarLambdaWithLocalClass.class.getTypeName();
+ ToolHelper.getClassFilesForInnerClasses(DesugarLambdaWithAnonymousClass.class));
+ String outer = DesugarLambdaWithAnonymousClass.class.getTypeName();
ClassSubject testClass = inspector.clazz(outer + "$TestClass");
assertThat(testClass, isPresent());
assertThat(testClass.uniqueMethodWithName("lambda$test$0"), isPresent());
assertThat(testClass.uniqueMethodWithName("lambda$testStatic$1"), isPresent());
- assertThat(inspector.clazz(outer + "$TestClass$1MyConsumerImpl"), isPresent());
- assertThat(inspector.clazz(outer + "$TestClass$2MyConsumerImpl"), isPresent());
+ assertThat(inspector.clazz(outer + "$TestClass$1"), isPresent());
+ assertThat(inspector.clazz(outer + "$TestClass$2"), isPresent());
}
@Test
- public void testDefault() throws Exception {
- if (parameters.getRuntime().isCf()) {
- // Run on the JVM.
- testForJvm()
+ public void testDesugar() throws Exception {
+ testForDesugaring(parameters)
+ .addInnerClasses(DesugarLambdaWithAnonymousClass.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .inspect(this::checkEnclosingMethod)
+ .applyIf(
+ DesugarTestConfiguration::isNotDesugared,
+ r -> r.assertSuccessWithOutputLines(EXPECTED_JAVAC_RESULT))
+ .applyIf(
+ DesugarTestConfiguration::isDesugared,
+ r -> r.assertSuccessWithOutputLines(EXPECTED_DESUGARED_RESULT));
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ try {
+ testForR8(parameters.getBackend())
+ // TODO(b/158752316, b/157700141): Disable inlining to keep the synthetic lambda methods.
+ .addOptionsModification(options -> options.enableInlining = false)
.addInnerClasses(DesugarLambdaWithAnonymousClass.class)
- .run(parameters.getRuntime(), TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepRules("-keep class * { *; }")
+ // Keeping the synthetic lambda methods is currently not supported - they are
+ // forcefully unpinned. The following rule has no effect. See b/b/157700141.
+ .addKeepRules("-keep class **.*$TestClass { synthetic *; }")
+ .addKeepAttributes("InnerClasses", "EnclosingMethod")
+ .compile()
.inspect(this::checkEnclosingMethod)
- .assertSuccessWithOutputLines(
- "Hello from inside lambda$test$0", "Hello from inside lambda$testStatic$1");
- } else {
- assert parameters.getRuntime().isDex();
- // Run on Art.
- checkArtResult(
- testForD8()
- .addInnerClasses(DesugarLambdaWithAnonymousClass.class)
- .setMinApi(parameters.getApiLevel())
- .compile()
- .inspect(this::checkEnclosingMethodWrong)
- .run(parameters.getRuntime(), TestClass.class));
- }
- }
-
- @Test
- public void testCfToCf() throws Exception {
- // Use D8 to desugar with Java classfile output.
- Path jar =
- testForD8(Backend.CF)
- .addInnerClasses(DesugarLambdaWithAnonymousClass.class)
- .setMinApi(parameters.getApiLevel())
- .compile()
- .inspect(this::checkEnclosingMethodWrong)
- .writeToZip();
-
- if (parameters.getRuntime().isCf()) {
- // Run on the JVM.
- testForJvm()
- .addProgramFiles(jar)
.run(parameters.getRuntime(), TestClass.class)
- // TODO(158752316): This should not fail.
- .assertFailureWithErrorThatThrows(InternalError.class);
- } else {
- assert parameters.getRuntime().isDex();
- // Compile to DEX without desugaring and run on Art.
- checkArtResult(
- testForD8()
- .addProgramFiles(jar)
- .setMinApi(parameters.getApiLevel())
- .disableDesugaring()
- .compile()
- .inspect(this::checkEnclosingMethodWrong)
- .run(parameters.getRuntime(), TestClass.class));
+ .assertSuccessWithOutputLines(
+ parameters.isCfRuntime() ? EXPECTED_JAVAC_RESULT : EXPECTED_DESUGARED_RESULT);
+ assertFalse(parameters.isDexRuntime());
+ } catch (AssertionError e) {
+ assertTrue(parameters.isDexRuntime());
}
}
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarLambdaWithLocalClass.java b/src/test/java/com/android/tools/r8/desugar/DesugarLambdaWithLocalClass.java
index 68fd89e..8c539d2 100644
--- a/src/test/java/com/android/tools/r8/desugar/DesugarLambdaWithLocalClass.java
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarLambdaWithLocalClass.java
@@ -5,22 +5,21 @@
package com.android.tools.r8.desugar;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
-import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.D8TestRunResult;
+import com.android.tools.r8.DesugarTestConfiguration;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
-import com.android.tools.r8.ToolHelper.DexVm.Version;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
-import java.nio.file.Path;
+import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
+import java.util.List;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -29,6 +28,17 @@
@RunWith(Parameterized.class)
public class DesugarLambdaWithLocalClass extends TestBase {
+ private List<String> EXPECTED_JAVAC_RESULT =
+ ImmutableList.of("Hello from inside lambda$test$0", "Hello from inside lambda$testStatic$1");
+
+ private List<String> EXPECTED_DESUGARED_RESULT =
+ ImmutableList.of(
+ "Hello from inside lambda$test$0$DesugarLambdaWithLocalClass$TestClass",
+ "Hello from inside lambda$testStatic$1");
+
+ private List<String> EXPECTED_DESUGARED_RESULT_R8_WITHOUT_INLINING =
+ ImmutableList.of("Hello from inside lambda$test$0", "Hello from inside lambda$testStatic$1");
+
@Parameterized.Parameters(name = "{0}")
public static TestParametersCollection data() {
return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
@@ -56,7 +66,8 @@
Counter counter = new Counter();
inspector.forAllClasses(
clazz -> {
- if (clazz.getFinalName().endsWith("MyConsumerImpl")) {
+ if (clazz.getFinalName().endsWith("$TestClass$1MyConsumerImpl")
+ || clazz.getFinalName().endsWith("$TestClass$2MyConsumerImpl")) {
counter.increment();
assertTrue(clazz.isLocalClass());
DexMethod enclosingMethod = clazz.getFinalEnclosingMethod();
@@ -71,111 +82,53 @@
assertEquals(2, counter.getCount());
}
- // TODO(158752316): There should be no use of this check.
- private void checkEnclosingMethodWrong(CodeInspector inspector) {
- Counter counter = new Counter();
- inspector.forAllClasses(
- clazz -> {
- if (clazz.getFinalName().endsWith("$TestClass$1MyConsumerImpl")
- || clazz.getFinalName().endsWith("$TestClass$2MyConsumerImpl")) {
- counter.increment();
- assertTrue(clazz.isLocalClass());
- DexMethod enclosingMethod = clazz.getFinalEnclosingMethod();
- ClassSubject testClassSubject = inspector.clazz(TestClass.class);
- assertEquals(
- testClassSubject, inspector.clazz(enclosingMethod.holder.toSourceString()));
- if (enclosingMethod.name.toString().contains("Static")) {
- assertThat(
- testClassSubject.uniqueMethodWithName(enclosingMethod.name.toString()),
- isPresent());
- } else {
- assertThat(
- testClassSubject.uniqueMethodWithName(enclosingMethod.name.toString()),
- not(isPresent()));
- }
- }
- });
- assertEquals(2, counter.getCount());
- }
-
- private void checkArtResult(D8TestRunResult result) {
- // TODO(158752316): This should neither return null nor fail.
- if (parameters.getRuntime().asDex().getVm().getVersion().isOlderThanOrEqual(Version.V4_4_4)
- || parameters.getRuntime().asDex().getVm().getVersion().isNewerThan(Version.V6_0_1)) {
- result.assertSuccessWithOutputLines(
- "Hello from inside <null>", "Hello from inside lambda$testStatic$1");
- } else {
- result.assertFailureWithErrorThatThrows(IncompatibleClassChangeError.class);
- }
- }
-
@BeforeClass
public static void checkExpectedJavacNames() throws Exception {
CodeInspector inspector =
new CodeInspector(
- ToolHelper.getClassFilesForInnerClasses(DesugarLambdaWithAnonymousClass.class));
- String outer = DesugarLambdaWithAnonymousClass.class.getTypeName();
+ ToolHelper.getClassFilesForInnerClasses(DesugarLambdaWithLocalClass.class));
+ String outer = DesugarLambdaWithLocalClass.class.getTypeName();
ClassSubject testClass = inspector.clazz(outer + "$TestClass");
assertThat(testClass, isPresent());
assertThat(testClass.uniqueMethodWithName("lambda$test$0"), isPresent());
assertThat(testClass.uniqueMethodWithName("lambda$testStatic$1"), isPresent());
- assertThat(inspector.clazz(outer + "$TestClass$1"), isPresent());
- assertThat(inspector.clazz(outer + "$TestClass$2"), isPresent());
+ assertThat(inspector.clazz(outer + "$TestClass$1MyConsumerImpl"), isPresent());
+ assertThat(inspector.clazz(outer + "$TestClass$2MyConsumerImpl"), isPresent());
}
@Test
- public void testDefault() throws Exception {
- if (parameters.getRuntime().isCf()) {
- // Run on the JVM.
- testForJvm()
- .addInnerClasses(DesugarLambdaWithLocalClass.class)
- .run(parameters.getRuntime(), TestClass.class)
- .inspect(this::checkEnclosingMethod)
- .assertSuccessWithOutputLines(
- "Hello from inside lambda$test$0", "Hello from inside lambda$testStatic$1");
- } else {
- assert parameters.getRuntime().isDex();
- // Run on Art.
- checkArtResult(
- testForD8()
- .addInnerClasses(DesugarLambdaWithLocalClass.class)
- .setMinApi(parameters.getApiLevel())
- .compile()
- .inspect(this::checkEnclosingMethodWrong)
- .run(parameters.getRuntime(), TestClass.class));
- }
+ public void testDesugar() throws Exception {
+ testForDesugaring(parameters)
+ .addInnerClasses(DesugarLambdaWithLocalClass.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .inspect(this::checkEnclosingMethod)
+ .applyIf(
+ DesugarTestConfiguration::isNotDesugared,
+ r -> r.assertSuccessWithOutputLines(EXPECTED_JAVAC_RESULT))
+ .applyIf(
+ DesugarTestConfiguration::isDesugared,
+ r -> r.assertSuccessWithOutputLines(EXPECTED_DESUGARED_RESULT));
}
@Test
- public void testCfToCf() throws Exception {
- // Use D8 to desugar with Java classfile output.
- Path jar =
- testForD8(Backend.CF)
- .addInnerClasses(DesugarLambdaWithLocalClass.class)
- .setMinApi(parameters.getApiLevel())
- .compile()
- .inspect(this::checkEnclosingMethodWrong)
- .writeToZip();
-
- if (parameters.getRuntime().isCf()) {
- // Run on the JVM.
- testForJvm()
- .addProgramFiles(jar)
- .run(parameters.getRuntime(), TestClass.class)
- // TODO(158752316): This should not fail.
- .assertFailureWithErrorThatThrows(InternalError.class);
- } else {
- assert parameters.getRuntime().isDex();
- // Compile to DEX without desugaring and run on Art.
- checkArtResult(
- testForD8()
- .addProgramFiles(jar)
- .setMinApi(parameters.getApiLevel())
- .disableDesugaring()
- .compile()
- .inspect(this::checkEnclosingMethodWrong)
- .run(parameters.getRuntime(), TestClass.class));
- }
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ // TODO(b/158752316, b/157700141): Disable inlining to keep the synthetic lambda methods.
+ .addOptionsModification(options -> options.enableInlining = false)
+ .addInnerClasses(DesugarLambdaWithLocalClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .addKeepRules("-keep class * { *; }")
+ // Keeping the synthetic lambda methods is currently not supported - they are
+ // forcefully unpinned. The following rule has no effect. See b/b/157700141.
+ .addKeepRules("-keep class **.*$TestClass { synthetic *; }")
+ .addKeepAttributes("InnerClasses", "EnclosingMethod")
+ .compile()
+ .inspect(this::checkEnclosingMethod)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines(
+ parameters.isCfRuntime()
+ ? EXPECTED_JAVAC_RESULT
+ : EXPECTED_DESUGARED_RESULT_R8_WITHOUT_INLINING);
}
public interface MyConsumer<T> {
diff --git a/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileBackport.java b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileBackport.java
new file mode 100644
index 0000000..e07089f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/DesugarToClassFileBackport.java
@@ -0,0 +1,120 @@
+// Copyright (c) 2020, 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.desugar;
+
+import static org.junit.Assert.assertTrue;
+
+import com.android.tools.r8.DesugarTestConfiguration;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.cf.code.CfArithmeticBinop;
+import com.android.tools.r8.cf.code.CfArithmeticBinop.Opcode;
+import com.android.tools.r8.cf.code.CfInstruction;
+import com.android.tools.r8.code.AddLong2Addr;
+import com.android.tools.r8.code.Instruction;
+import com.android.tools.r8.graph.CfCode;
+import com.android.tools.r8.graph.DexCode;
+import com.android.tools.r8.ir.code.NumericType;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.android.tools.r8.utils.codeinspector.InstructionSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
+import java.util.Arrays;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class DesugarToClassFileBackport extends TestBase {
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withAllApiLevelsAlsoForCf().build();
+ }
+
+ private final TestParameters parameters;
+
+ public DesugarToClassFileBackport(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ private boolean isCfLAdd(CfInstruction instruction) {
+ return (instruction instanceof CfArithmeticBinop)
+ && (((CfArithmeticBinop) instruction).getOpcode() == Opcode.Add)
+ && (((CfArithmeticBinop) instruction).getType() == NumericType.LONG);
+ }
+
+ private boolean isDexAddLong(Instruction instruction) {
+ return instruction instanceof AddLong2Addr;
+ }
+
+ private boolean boxedDoubleIsFiniteInvoke(InstructionSubject instruction) {
+ System.out.println(instruction);
+ if (instruction.isInvokeStatic()) {
+ System.out.println(instruction.getMethod().qualifiedName());
+ }
+ return instruction.isInvokeStatic()
+ && instruction.getMethod().qualifiedName().equals("java.lang.Double.isFinite");
+ }
+
+ private void checkBackportingNotRequired(CodeInspector inspector) {
+ MethodSubject methodSubject = inspector.clazz(TestClass.class).uniqueMethodWithName("main");
+ if (methodSubject.getProgramMethod().getDefinition().getCode().isCfCode()) {
+ CfCode code = methodSubject.getProgramMethod().getDefinition().getCode().asCfCode();
+ assertTrue(code.instructions.stream().noneMatch(this::isCfLAdd));
+ } else {
+ DexCode code = methodSubject.getProgramMethod().getDefinition().getCode().asDexCode();
+ assertTrue(Arrays.stream(code.instructions).noneMatch(this::isDexAddLong));
+ }
+ assertTrue(methodSubject.streamInstructions().anyMatch(this::boxedDoubleIsFiniteInvoke));
+ }
+
+ private void checkBackportingRequired(CodeInspector inspector) {
+ MethodSubject methodSubject = inspector.clazz(TestClass.class).uniqueMethodWithName("main");
+ if (methodSubject.getProgramMethod().getDefinition().getCode().isCfCode()) {
+ CfCode code = methodSubject.getProgramMethod().getDefinition().getCode().asCfCode();
+ assertTrue(code.instructions.stream().anyMatch(this::isCfLAdd));
+ } else {
+ DexCode code = methodSubject.getProgramMethod().getDefinition().getCode().asDexCode();
+ assertTrue(Arrays.stream(code.instructions).anyMatch(this::isDexAddLong));
+ }
+ assertTrue(methodSubject.streamInstructions().noneMatch(this::boxedDoubleIsFiniteInvoke));
+ }
+
+ private void checkBackportedIfRequired(CodeInspector inspector) {
+ if (parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N)) {
+ checkBackportingNotRequired(inspector);
+ } else {
+ checkBackportingRequired(inspector);
+ }
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForDesugaring(parameters)
+ .addInnerClasses(DesugarToClassFileBackport.class)
+ .run(parameters.getRuntime(), TestClass.class)
+ .inspectIf(DesugarTestConfiguration::isNotDesugared, this::checkBackportingNotRequired)
+ .inspectIf(DesugarTestConfiguration::isDesugared, this::checkBackportedIfRequired)
+ .assertSuccessWithOutputLines("3", "true");
+ }
+
+ static class TestClass {
+
+ private static long getOne() {
+ return 1L;
+ }
+
+ private static long getTwo() {
+ return 2L;
+ }
+
+ public static void main(String[] args) {
+ System.out.println(Long.sum(getOne(), getTwo()));
+ System.out.println(Double.isFinite(1.0));
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/BackportDuplicationTest.java b/src/test/java/com/android/tools/r8/desugar/backports/BackportDuplicationTest.java
new file mode 100644
index 0000000..2913fe5
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/BackportDuplicationTest.java
@@ -0,0 +1,167 @@
+// Copyright (c) 2020, 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.desugar.backports;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.hasItems;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest.MiniAssert;
+import com.android.tools.r8.synthesis.SyntheticItems;
+import com.android.tools.r8.utils.AndroidApiLevel;
+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.FoundMethodSubject;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class BackportDuplicationTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("Hello, world");
+
+ static final List<Class<?>> CLASSES =
+ ImmutableList.of(MiniAssert.class, TestClass.class, User1.class, User2.class);
+
+ static final List<String> CLASS_TYPE_NAMES =
+ CLASSES.stream().map(Class::getTypeName).collect(Collectors.toList());
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimes().withApiLevel(AndroidApiLevel.J).build();
+ }
+
+ public BackportDuplicationTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ runR8(false);
+ runR8(true);
+ }
+
+ private void runR8(boolean minify) throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(CLASSES)
+ .addKeepMainRule(TestClass.class)
+ .addKeepClassAndMembersRules(MiniAssert.class)
+ .setMinApi(parameters.getApiLevel())
+ .minification(minify)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(this::checkNoInternalSyntheticNames);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ List<String> run1 = getClassesAfterD8CompileAndRun();
+ List<String> run2 = getClassesAfterD8CompileAndRun();
+ assertEquals("Non deterministic synthesis", run1, run2);
+ }
+
+ private List<String> getClassesAfterD8CompileAndRun() throws Exception {
+ return testForD8(parameters.getBackend())
+ .addProgramClasses(CLASSES)
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutput(EXPECTED)
+ .inspect(this::checkNoInternalSyntheticNames)
+ .inspect(this::checkExpectedOutput)
+ .inspector()
+ .allClasses()
+ .stream()
+ .filter(c -> !CLASS_TYPE_NAMES.contains(c.getFinalName()))
+ .flatMap(c -> c.allMethods().stream().map(m -> m.asMethodReference().toString()))
+ .sorted()
+ .collect(Collectors.toList());
+ }
+
+ private void checkNoInternalSyntheticNames(CodeInspector inspector) {
+ inspector.forAllClasses(
+ clazz -> {
+ assertThat(
+ clazz.getFinalName(),
+ not(containsString(SyntheticItems.INTERNAL_SYNTHETIC_CLASS_SEPARATOR)));
+ });
+ }
+
+ private void checkExpectedOutput(CodeInspector inspector) {
+ // TODO(b/158159959): Once synthetic methods can be grouped in classes this should become 1.
+ int expectedSynthesizedClasses = 3;
+ // Total number of synthetic methods should be 3 ({Boolean,Character,Long}.compare).
+ int expectedSynthesizedMethods = 3;
+ // Desugaring should add exactly one class with one desugared method.
+ assertEquals(expectedSynthesizedClasses, inspector.allClasses().size() - CLASSES.size());
+ assertThat(
+ inspector.allClasses().stream()
+ .map(ClassSubject::getOriginalName)
+ .collect(Collectors.toList()),
+ hasItems(CLASS_TYPE_NAMES.toArray()));
+ List<FoundMethodSubject> methods =
+ inspector.allClasses().stream()
+ .filter(clazz -> !CLASS_TYPE_NAMES.contains(clazz.getOriginalName()))
+ .flatMap(clazz -> clazz.allMethods().stream())
+ .collect(Collectors.toList());
+ assertEquals(expectedSynthesizedMethods, methods.size());
+ }
+
+ static class User1 {
+
+ private static void testBooleanCompare() {
+ // These 4 calls should share the same synthetic method.
+ MiniAssert.assertTrue(Boolean.compare(true, false) > 0);
+ MiniAssert.assertTrue(Boolean.compare(true, true) == 0);
+ MiniAssert.assertTrue(Boolean.compare(false, false) == 0);
+ MiniAssert.assertTrue(Boolean.compare(false, true) < 0);
+ }
+
+ private static void testCharacterCompare() {
+ // All 6 (User1 and User2) calls should share the same synthetic method.
+ MiniAssert.assertTrue(Character.compare('b', 'a') > 0);
+ MiniAssert.assertTrue(Character.compare('a', 'a') == 0);
+ MiniAssert.assertTrue(Character.compare('a', 'b') < 0);
+ }
+ }
+
+ static class User2 {
+
+ private static void testCharacterCompare() {
+ // All 6 (User1 and User2) calls should share the same synthetic method.
+ MiniAssert.assertTrue(Character.compare('y', 'x') > 0);
+ MiniAssert.assertTrue(Character.compare('x', 'x') == 0);
+ MiniAssert.assertTrue(Character.compare('x', 'y') < 0);
+ }
+
+ private static void testIntegerCompare() {
+ // These 3 calls should share the same synthetic method.
+ MiniAssert.assertTrue(Integer.compare(2, 0) > 0);
+ MiniAssert.assertTrue(Integer.compare(0, 0) == 0);
+ MiniAssert.assertTrue(Integer.compare(0, 2) < 0);
+ }
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ User1.testBooleanCompare();
+ User1.testCharacterCompare();
+ User2.testCharacterCompare();
+ User2.testIntegerCompare();
+ System.out.println("Hello, world");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java b/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java
new file mode 100644
index 0000000..3be0a2c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/desugar/backports/BackportMainDexTest.java
@@ -0,0 +1,253 @@
+// Copyright (c) 2020, 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.desugar.backports;
+
+import static com.android.tools.r8.synthesis.SyntheticItems.EXTERNAL_SYNTHETIC_CLASS_SEPARATOR;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assume.assumeTrue;
+
+import com.android.tools.r8.ByteDataView;
+import com.android.tools.r8.DexIndexedConsumer;
+import com.android.tools.r8.DiagnosticsHandler;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.desugar.backports.AbstractBackportTest.MiniAssert;
+import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.references.Reference;
+import com.android.tools.r8.utils.AndroidApiLevel;
+import com.android.tools.r8.utils.AndroidApp;
+import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import java.util.Set;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class BackportMainDexTest extends TestBase {
+
+ static final String EXPECTED = StringUtils.lines("Hello, world");
+
+ static final List<Class<?>> CLASSES =
+ ImmutableList.of(MiniAssert.class, TestClass.class, User1.class, User2.class);
+
+ static final String SyntheticUnderUser1 =
+ User1.class.getTypeName() + EXTERNAL_SYNTHETIC_CLASS_SEPARATOR;
+ static final String SyntheticUnderUser2 =
+ User2.class.getTypeName() + EXTERNAL_SYNTHETIC_CLASS_SEPARATOR;
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimes().withApiLevel(AndroidApiLevel.J).build();
+ }
+
+ public BackportMainDexTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ private String[] getRunArgs() {
+ // Only call User1 methods on runtimes with native multidex.
+ if (parameters.isCfRuntime()
+ || parameters
+ .getRuntime()
+ .asDex()
+ .getMinApiLevel()
+ .isGreaterThanOrEqualTo(apiLevelWithNativeMultiDexSupport())) {
+ return new String[] {User1.class.getTypeName()};
+ }
+ return new String[0];
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addProgramClasses(CLASSES)
+ .run(parameters.getRuntime(), TestClass.class, getRunArgs())
+ .assertSuccessWithOutput(EXPECTED);
+ }
+
+ @Test
+ public void testD8() throws Exception {
+ assumeTrue(parameters.isDexRuntime());
+ Set<String> mainDex1 = runD8();
+ Set<String> mainDex2 = runD8();
+ assertEquals("Expected deterministic main-dex lists", mainDex1, mainDex2);
+ }
+
+ private Set<String> runD8() throws Exception {
+ MainDexConsumer mainDexConsumer = new MainDexConsumer();
+ testForD8(parameters.getBackend())
+ .addProgramClasses(CLASSES)
+ .setMinApi(parameters.getApiLevel())
+ .addMainDexListClasses(MiniAssert.class, TestClass.class, User2.class)
+ .setProgramConsumer(mainDexConsumer)
+ .compile()
+ .inspect(
+ inspector -> {
+ // Note: This will change if we group methods in classes, in which case we should
+ // preferable not put non-main-dex referenced methods in the main-dex group.
+ // User1 has two synthetics, one shared with User2 and one for self.
+ assertEquals(
+ 2,
+ inspector.allClasses().stream()
+ .filter(c -> c.getFinalName().startsWith(SyntheticUnderUser1))
+ .count());
+ // User2 has one synthetic as the shared call is placed in User1.
+ assertEquals(
+ 1,
+ inspector.allClasses().stream()
+ .filter(c -> c.getFinalName().startsWith(SyntheticUnderUser2))
+ .count());
+ })
+ .run(parameters.getRuntime(), TestClass.class, getRunArgs())
+ .assertSuccessWithOutput(EXPECTED);
+ checkMainDex(mainDexConsumer);
+ return mainDexConsumer.mainDexDescriptors;
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ Set<String> mainDex1 = runR8();
+ if (parameters.isDexRuntime()) {
+ Set<String> mainDex2 = runR8();
+ assertEquals(mainDex1, mainDex2);
+ }
+ }
+
+ private Set<String> runR8() throws Exception {
+ MainDexConsumer mainDexConsumer = parameters.isDexRuntime() ? new MainDexConsumer() : null;
+ testForR8(parameters.getBackend())
+ .debug() // Use debug mode to force a minimal main dex.
+ .noMinification() // Disable minification so we can inspect the synthetic names.
+ .applyIf(mainDexConsumer != null, b -> b.setProgramConsumer(mainDexConsumer))
+ .addProgramClasses(CLASSES)
+ .addKeepMainRule(TestClass.class)
+ .addKeepClassAndMembersRules(MiniAssert.class)
+ .addMainDexClassRules(MiniAssert.class, TestClass.class)
+ .addKeepMethodRules(
+ Reference.methodFromMethod(User1.class.getMethod("testBooleanCompare")),
+ Reference.methodFromMethod(User1.class.getMethod("testCharacterCompare")))
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), TestClass.class, getRunArgs())
+ .assertSuccessWithOutput(EXPECTED);
+ if (mainDexConsumer != null) {
+ checkMainDex(mainDexConsumer);
+ return mainDexConsumer.mainDexDescriptors;
+ }
+ return null;
+ }
+
+ private void checkMainDex(MainDexConsumer mainDexConsumer) throws Exception {
+ AndroidApp mainDexApp =
+ AndroidApp.builder()
+ .addDexProgramData(mainDexConsumer.mainDexBytes, Origin.unknown())
+ .build();
+ CodeInspector mainDexInspector = new CodeInspector(mainDexApp);
+
+ // The program classes in the main-dex list must be in main-dex.
+ assertThat(mainDexInspector.clazz(MiniAssert.class), isPresent());
+ assertThat(mainDexInspector.clazz(TestClass.class), isPresent());
+ assertThat(mainDexInspector.clazz(User2.class), isPresent());
+
+ // At least one synthetic class placed under User2 must be included in the main-dex file.
+ assertEquals(
+ 1,
+ mainDexInspector.allClasses().stream()
+ .filter(c -> c.getFinalName().startsWith(SyntheticUnderUser2))
+ .count());
+
+ // Minimal main dex should only include one of the User1 synthetics.
+ assertThat(mainDexInspector.clazz(User1.class), not(isPresent()));
+ assertEquals(
+ 1,
+ mainDexInspector.allClasses().stream()
+ .filter(c -> c.getFinalName().startsWith(SyntheticUnderUser1))
+ .count());
+ assertThat(mainDexInspector.clazz(SyntheticUnderUser1), not(isPresent()));
+ }
+
+ static class User1 {
+
+ public static void testBooleanCompare() {
+ // These 4 calls should share the same synthetic method.
+ MiniAssert.assertTrue(Boolean.compare(true, false) > 0);
+ MiniAssert.assertTrue(Boolean.compare(true, true) == 0);
+ MiniAssert.assertTrue(Boolean.compare(false, false) == 0);
+ MiniAssert.assertTrue(Boolean.compare(false, true) < 0);
+ }
+
+ public static void testCharacterCompare() {
+ // All 6 (User1 and User2) calls should share the same synthetic method.
+ MiniAssert.assertTrue(Character.compare('b', 'a') > 0);
+ MiniAssert.assertTrue(Character.compare('a', 'a') == 0);
+ MiniAssert.assertTrue(Character.compare('a', 'b') < 0);
+ }
+ }
+
+ static class User2 {
+
+ public static void testCharacterCompare() {
+ // All 6 (User1 and User2) calls should share the same synthetic method.
+ MiniAssert.assertTrue(Character.compare('y', 'x') > 0);
+ MiniAssert.assertTrue(Character.compare('x', 'x') == 0);
+ MiniAssert.assertTrue(Character.compare('x', 'y') < 0);
+ }
+
+ public static void testIntegerCompare() {
+ // These 3 calls should share the same synthetic method.
+ MiniAssert.assertTrue(Integer.compare(2, 0) > 0);
+ MiniAssert.assertTrue(Integer.compare(0, 0) == 0);
+ MiniAssert.assertTrue(Integer.compare(0, 2) < 0);
+ }
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) throws Exception {
+ if (args.length == 1) {
+ // Reflectively call the backports on User1 which is not in the main-dex list.
+ Class<?> user1 = Class.forName(args[0]);
+ user1.getMethod("testBooleanCompare").invoke(user1);
+ user1.getMethod("testCharacterCompare").invoke(user1);
+ }
+ User2.testCharacterCompare();
+ User2.testIntegerCompare();
+ System.out.println("Hello, world");
+ }
+ }
+
+ private static class MainDexConsumer implements DexIndexedConsumer {
+
+ byte[] mainDexBytes;
+ Set<String> mainDexDescriptors;
+
+ @Override
+ public void accept(
+ int fileIndex, ByteDataView data, Set<String> descriptors, DiagnosticsHandler handler) {
+ if (fileIndex == 0) {
+ assertNull(mainDexBytes);
+ assertNull(mainDexDescriptors);
+ mainDexBytes = data.copyByteData();
+ mainDexDescriptors = descriptors;
+ }
+ }
+
+ @Override
+ public void finished(DiagnosticsHandler handler) {
+ assertNotNull(mainDexBytes);
+ assertNotNull(mainDexDescriptors);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/backports/DesugarStaticBackportsOnly.java b/src/test/java/com/android/tools/r8/desugar/backports/DesugarStaticBackportsOnly.java
index cd6d160..77e088c 100644
--- a/src/test/java/com/android/tools/r8/desugar/backports/DesugarStaticBackportsOnly.java
+++ b/src/test/java/com/android/tools/r8/desugar/backports/DesugarStaticBackportsOnly.java
@@ -17,6 +17,7 @@
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.synthesis.SyntheticItems;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.InternalOptions.DesugarState;
import com.android.tools.r8.utils.StringUtils;
@@ -55,7 +56,7 @@
instructionSubject.isInvokeStatic()
&& instructionSubject
.toString()
- .contains("$r8$backportedMethods$utility$Long$1$hashCode")));
+ .contains(SyntheticItems.EXTERNAL_SYNTHETIC_CLASS_SEPARATOR)));
assertEquals(
parameters.getApiLevel().isGreaterThanOrEqualTo(AndroidApiLevel.N),
classSubject
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
index 1b46018..d99b31f 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/DesugaredLibraryContentTest.java
@@ -6,6 +6,7 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static junit.framework.TestCase.assertTrue;
+import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertFalse;
@@ -84,7 +85,7 @@
}
private void assertCorrect(CodeInspector inspector) {
- inspector.allClasses().forEach(clazz -> assertTrue(clazz.getOriginalName().startsWith("j$.")));
+ inspector.allClasses().forEach(clazz -> assertThat(clazz.getOriginalName(), startsWith("j$.")));
assertThat(inspector.clazz("j$.time.Clock"), isPresent());
// Above N the following classes are removed instead of being desugared.
if (parameters.getApiLevel().getLevel() >= AndroidApiLevel.N.getLevel()) {
diff --git a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java
index adaa55f..b15c928 100644
--- a/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/desugaring/interfacemethods/InvokeSuperInDefaultInterfaceMethodTest.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.desugaring.interfacemethods;
import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
@@ -23,7 +23,7 @@
.addInnerClasses(InvokeSuperInDefaultInterfaceMethodTest.class)
.addKeepMainRule(TestClass.class)
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(AndroidApiLevel.M)
.run(TestClass.class)
.assertSuccessWithOutput(expectedOutput);
@@ -37,7 +37,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
default void m() {
@@ -45,7 +45,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface J extends I {
@Override
@@ -55,7 +55,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface K extends I {
// Intentionally does not override I.m().
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterInlineRegression.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterInlineRegression.java
index 3e3a02c..278d99c 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterInlineRegression.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterInlineRegression.java
@@ -13,7 +13,7 @@
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestParameters;
@@ -56,7 +56,8 @@
assertThat(clazz.uniqueMethodWithName("getFromFeature"), not(isPresent()));
};
Consumer<R8FullTestBuilder> configurator =
- r8FullTestBuilder -> r8FullTestBuilder.enableMergeAnnotations().noMinification();
+ r8FullTestBuilder ->
+ r8FullTestBuilder.enableNoVerticalClassMergingAnnotations().noMinification();
ProcessResult processResult =
testDexSplitter(
parameters,
@@ -75,7 +76,8 @@
public void testOnR8Splitter() throws IOException, CompilationFailedException {
assumeTrue(parameters.isDexRuntime());
Consumer<R8FullTestBuilder> configurator =
- r8FullTestBuilder -> r8FullTestBuilder.enableMergeAnnotations().noMinification();
+ r8FullTestBuilder ->
+ r8FullTestBuilder.enableNoVerticalClassMergingAnnotations().noMinification();
ProcessResult processResult =
testR8Splitter(
parameters,
@@ -89,7 +91,7 @@
assertEquals(processResult.stdout, StringUtils.lines("42"));
}
- @NeverMerge
+ @NoVerticalClassMerging
public abstract static class BaseSuperClass implements RunInterface {
@Override
public void run() {
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java
index 5a0fd21..c9dd274 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterMergeRegression.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestParameters;
@@ -60,7 +60,7 @@
Consumer<R8FullTestBuilder> configurator =
r8FullTestBuilder ->
r8FullTestBuilder
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableInliningAnnotations()
.noMinification()
.addOptionsModification(o -> o.testing.deterministicSortingBasedOnDexType = true);
@@ -82,7 +82,8 @@
public void testOnR8Splitter() throws IOException, CompilationFailedException {
assumeTrue(parameters.isDexRuntime());
Consumer<R8FullTestBuilder> configurator =
- r8FullTestBuilder -> r8FullTestBuilder.enableMergeAnnotations().noMinification();
+ r8FullTestBuilder ->
+ r8FullTestBuilder.enableNoVerticalClassMergingAnnotations().noMinification();
ProcessResult processResult =
testR8Splitter(
parameters,
@@ -96,7 +97,7 @@
assertTrue(processResult.stdout.equals(StringUtils.lines("42", "foobar")));
}
- @NeverMerge
+ @NoVerticalClassMerging
public static class BaseClass implements RunInterface {
@Override
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/R8FeatureSplitServiceLoaderTest.java b/src/test/java/com/android/tools/r8/dexsplitter/R8FeatureSplitServiceLoaderTest.java
index c290f26..9e116da 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/R8FeatureSplitServiceLoaderTest.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/R8FeatureSplitServiceLoaderTest.java
@@ -5,8 +5,11 @@
package com.android.tools.r8.dexsplitter;
import static com.android.tools.r8.rewrite.ServiceLoaderRewritingTest.getServiceLoaderLoads;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.StringContains.containsString;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
import com.android.tools.r8.DataEntryResource;
import com.android.tools.r8.R8TestRunResult;
@@ -103,45 +106,31 @@
@Test
public void testR8AllLoaded() throws Exception {
- Path base = temp.newFile("base.zip").toPath();
- Path feature1Path = temp.newFile("feature1.zip").toPath();
- Path feature2Path = temp.newFile("feature2.zip").toPath();
R8TestRunResult runResult =
testForR8(parameters.getBackend())
.addProgramClasses(Base.class, I.class)
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(Base.class)
- .addFeatureSplit(
- builder ->
- splitWithNonJavaFile(
- builder,
- feature1Path,
- temp,
- ImmutableList.of(
- new Pair<>(
- "META-INF/services/" + I.class.getTypeName(),
- StringUtils.lines(Feature1I.class.getTypeName()))),
- true,
- Feature1I.class))
- .addFeatureSplit(
- builder ->
- splitWithNonJavaFile(
- builder,
- feature2Path,
- temp,
- ImmutableList.of(
- new Pair<>(
- "META-INF/services/" + I.class.getTypeName(),
- StringUtils.lines(Feature2I.class.getTypeName()))),
- true,
- Feature2I.class))
+ .addFeatureSplitWithResources(
+ ImmutableList.of(
+ new Pair<>(
+ "META-INF/services/" + I.class.getTypeName(),
+ StringUtils.lines(Feature1I.class.getTypeName()))),
+ Feature1I.class)
+ .addFeatureSplitWithResources(
+ ImmutableList.of(
+ new Pair<>(
+ "META-INF/services/" + I.class.getTypeName(),
+ StringUtils.lines(Feature2I.class.getTypeName()))),
+ Feature2I.class)
.compile()
.inspect(
- inspector -> {
- assertEquals(1, getServiceLoaderLoads(inspector, Base.class));
- })
- .writeToZip(base)
- .addRunClasspathFiles(feature1Path, feature2Path)
+ baseInspector -> assertEquals(1, getServiceLoaderLoads(baseInspector, Base.class)),
+ feature1Inspector ->
+ assertThat(feature1Inspector.clazz(Feature1I.class), isPresent()),
+ feature2Inspector ->
+ assertThat(feature2Inspector.clazz(Feature2I.class), isPresent()))
+ .addFeatureSplitsToRunClasspathFiles()
.run(parameters.getRuntime(), Base.class);
// TODO(b/160888348): This is failing on 7.0
if (parameters.getRuntime().isDex()
@@ -154,39 +143,29 @@
@Test
public void testR8WithServiceFileInSeparateFeature() throws Exception {
- Path base = temp.newFile("base.zip").toPath();
- Path feature1Path = temp.newFile("feature1.zip").toPath();
- Path feature2Path = temp.newFile("feature2.zip").toPath();
- Path feature3Path = temp.newFile("feature3.zip").toPath();
R8TestRunResult runResult =
testForR8(parameters.getBackend())
.addProgramClasses(Base.class, I.class)
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(Base.class)
- .addFeatureSplit(
- builder -> simpleSplitProvider(builder, feature1Path, temp, Feature1I.class))
- .addFeatureSplit(
- builder -> simpleSplitProvider(builder, feature2Path, temp, Feature2I.class))
- .addFeatureSplit(
- builder ->
- splitWithNonJavaFile(
- builder,
- feature3Path,
- temp,
- ImmutableList.of(
- new Pair<>(
- "META-INF/services/" + I.class.getTypeName(),
- StringUtils.lines(
- Feature1I.class.getTypeName(), Feature2I.class.getTypeName()))),
- true,
- Feature3Dummy.class))
+ .addFeatureSplit(Feature1I.class)
+ .addFeatureSplit(Feature2I.class)
+ .addFeatureSplitWithResources(
+ ImmutableList.of(
+ new Pair<>(
+ "META-INF/services/" + I.class.getTypeName(),
+ StringUtils.lines(
+ Feature1I.class.getTypeName(), Feature2I.class.getTypeName()))),
+ Feature3Dummy.class)
.compile()
.inspect(
- inspector -> {
- assertEquals(1, getServiceLoaderLoads(inspector, Base.class));
- })
- .writeToZip(base)
- .addRunClasspathFiles(feature1Path, feature2Path, feature3Path)
+ baseInspector -> assertEquals(1, getServiceLoaderLoads(baseInspector, Base.class)),
+ feature1Inspector ->
+ assertThat(feature1Inspector.clazz(Feature1I.class), isPresent()),
+ feature2Inspector ->
+ assertThat(feature2Inspector.clazz(Feature2I.class), isPresent()),
+ feature3Inspector -> assertTrue(feature3Inspector.allClasses().isEmpty()))
+ .addFeatureSplitsToRunClasspathFiles()
.run(parameters.getRuntime(), Base.class);
// TODO(b/160888348): This is failing on 7.0
if (parameters.getRuntime().isDex()
@@ -199,44 +178,28 @@
@Test
public void testR8OnlyFeature2() throws Exception {
- Path base = temp.newFile("base.zip").toPath();
- Path feature1Path = temp.newFile("feature1.zip").toPath();
- Path feature2Path = temp.newFile("feature2.zip").toPath();
testForR8(parameters.getBackend())
.addProgramClasses(Base.class, I.class)
.setMinApi(parameters.getApiLevel())
.addKeepMainRule(Base.class)
- .addFeatureSplit(
- builder ->
- splitWithNonJavaFile(
- builder,
- feature1Path,
- temp,
- ImmutableList.of(
- new Pair<>(
- "META-INF/services/" + I.class.getTypeName(),
- StringUtils.lines(Feature1I.class.getTypeName()))),
- true,
- Feature1I.class))
- .addFeatureSplit(
- builder ->
- splitWithNonJavaFile(
- builder,
- feature2Path,
- temp,
- ImmutableList.of(
- new Pair<>(
- "META-INF/services/" + I.class.getTypeName(),
- StringUtils.lines(Feature2I.class.getTypeName()))),
- true,
- Feature2I.class))
+ .addFeatureSplitWithResources(
+ ImmutableList.of(
+ new Pair<>(
+ "META-INF/services/" + I.class.getTypeName(),
+ StringUtils.lines(Feature1I.class.getTypeName()))),
+ Feature1I.class)
+ .addFeatureSplitWithResources(
+ ImmutableList.of(
+ new Pair<>(
+ "META-INF/services/" + I.class.getTypeName(),
+ StringUtils.lines(Feature2I.class.getTypeName()))),
+ Feature2I.class)
.compile()
.inspect(
- inspector -> {
- assertEquals(1, getServiceLoaderLoads(inspector, Base.class));
- })
- .writeToZip(base)
- .addRunClasspathFiles(feature2Path)
+ baseInspector -> assertEquals(1, getServiceLoaderLoads(baseInspector, Base.class)),
+ feature1Inspector -> assertThat(feature1Inspector.clazz(Feature1I.class), isPresent()),
+ feature2Inspector -> assertThat(feature2Inspector.clazz(Feature2I.class), isPresent()))
+ .apply(compileResult -> compileResult.addRunClasspathFiles(compileResult.getFeature(1)))
.run(parameters.getRuntime(), Base.class)
// TODO(b/160889305): This should work.
.assertFailureWithErrorThatMatches(containsString("java.lang.ClassNotFoundException"));
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/R8FeatureSplitTest.java b/src/test/java/com/android/tools/r8/dexsplitter/R8FeatureSplitTest.java
index 60477b6..b5940d4 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/R8FeatureSplitTest.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/R8FeatureSplitTest.java
@@ -13,6 +13,7 @@
import com.android.tools.r8.DexIndexedConsumer;
import com.android.tools.r8.ExtractMarker;
import com.android.tools.r8.FeatureSplit;
+import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.ResourceException;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -131,12 +132,11 @@
.setMinApi(parameters.getApiLevel())
.addFeatureSplit(
builder ->
- splitWithNonJavaFile(
- builder, feature1Path, temp, nonJavaFiles, true, FeatureClass.class))
+ splitWithNonJavaFile(builder, feature1Path, temp, nonJavaFiles, FeatureClass.class))
.addFeatureSplit(
builder ->
splitWithNonJavaFile(
- builder, feature2Path, temp, nonJavaFiles, true, FeatureClass2.class))
+ builder, feature2Path, temp, nonJavaFiles, FeatureClass2.class))
.addKeepAllClassesRule()
.compile()
.writeToZip(basePath);
@@ -158,32 +158,23 @@
@Test
public void testAdaptResourceContentInSplits() throws IOException, CompilationFailedException {
- Path basePath = temp.newFile("base.zip").toPath();
- Path feature1Path = temp.newFile("feature1.zip").toPath();
- Path feature2Path = temp.newFile("feature2.zip").toPath();
// Make the content of the data resource be class names
Collection<Pair<String, String>> nonJavaFiles =
ImmutableList.of(
new Pair<>(FeatureClass.class.getName(), FeatureClass.class.getName()),
new Pair<>(FeatureClass2.class.getName(), FeatureClass2.class.getName()));
- testForR8(parameters.getBackend())
- .addProgramClasses(BaseClass.class, RunInterface.class, SplitRunner.class)
- .setMinApi(parameters.getApiLevel())
- .addFeatureSplit(
- builder ->
- splitWithNonJavaFile(
- builder, feature1Path, temp, nonJavaFiles, false, FeatureClass.class))
- .addFeatureSplit(
- builder ->
- splitWithNonJavaFile(
- builder, feature2Path, temp, nonJavaFiles, false, FeatureClass2.class))
- .addKeepClassRulesWithAllowObfuscation(
- BaseClass.class, FeatureClass.class, FeatureClass2.class)
- .addKeepRules("-adaptresourcefilecontents")
- .compile()
- .writeToZip(basePath);
- for (Path feature : ImmutableList.of(feature1Path, feature2Path)) {
+ R8TestCompileResult compileResult =
+ testForR8(parameters.getBackend())
+ .addProgramClasses(BaseClass.class, RunInterface.class, SplitRunner.class)
+ .setMinApi(parameters.getApiLevel())
+ .addFeatureSplitWithResources(nonJavaFiles, FeatureClass.class)
+ .addFeatureSplitWithResources(nonJavaFiles, FeatureClass2.class)
+ .addKeepClassRulesWithAllowObfuscation(
+ BaseClass.class, FeatureClass.class, FeatureClass2.class)
+ .addKeepRules("-adaptresourcefilecontents")
+ .compile();
+ for (Path feature : compileResult.getFeatures()) {
ZipFile zipFile = new ZipFile(feature.toFile());
for (Pair<String, String> nonJavaFile : nonJavaFiles) {
ZipEntry entry = zipFile.getEntry(nonJavaFile.getFirst());
@@ -192,7 +183,7 @@
assertNotEquals(content, nonJavaFile.getSecond());
}
}
- ZipFile zipFile = new ZipFile(basePath.toFile());
+ ZipFile zipFile = new ZipFile(compileResult.writeToZip().toFile());
for (Pair<String, String> nonJavaFile : nonJavaFiles) {
ZipEntry entry = zipFile.getEntry(nonJavaFile.getFirst());
assertNull(entry);
@@ -259,20 +250,17 @@
public CompiledWithFeature invoke() throws IOException, CompilationFailedException {
- basePath = temp.newFile("base.zip").toPath();
- feature1Path = temp.newFile("feature1.zip").toPath();
- feature2Path = temp.newFile("feature2.zip").toPath();
-
- testForR8(parameters.getBackend())
- .addProgramClasses(BaseClass.class, RunInterface.class, SplitRunner.class)
- .setMinApi(parameters.getApiLevel())
- .addFeatureSplit(
- builder -> simpleSplitProvider(builder, feature1Path, temp, FeatureClass.class))
- .addFeatureSplit(
- builder -> simpleSplitProvider(builder, feature2Path, temp, FeatureClass2.class))
- .addKeepAllClassesRule()
- .compile()
- .writeToZip(basePath);
+ R8TestCompileResult compileResult =
+ testForR8(parameters.getBackend())
+ .addProgramClasses(BaseClass.class, RunInterface.class, SplitRunner.class)
+ .setMinApi(parameters.getApiLevel())
+ .addFeatureSplit(FeatureClass.class)
+ .addFeatureSplit(FeatureClass2.class)
+ .addKeepAllClassesRule()
+ .compile();
+ basePath = compileResult.writeToZip();
+ feature1Path = compileResult.getFeature(0);
+ feature2Path = compileResult.getFeature(1);
return this;
}
}
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/R8SplitterInlineToFeature.java b/src/test/java/com/android/tools/r8/dexsplitter/R8SplitterInlineToFeature.java
index def7782..46ac75d 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/R8SplitterInlineToFeature.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/R8SplitterInlineToFeature.java
@@ -10,7 +10,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.R8FullTestBuilder;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestParameters;
@@ -50,7 +50,8 @@
public void testInlining() throws Exception {
assumeTrue(parameters.isDexRuntime());
Consumer<R8FullTestBuilder> configurator =
- r8FullTestBuilder -> r8FullTestBuilder.enableMergeAnnotations().noMinification();
+ r8FullTestBuilder ->
+ r8FullTestBuilder.enableNoVerticalClassMergingAnnotations().noMinification();
ThrowingConsumer<R8TestCompileResult, Exception> ensureInlined =
r8TestCompileResult -> {
// Ensure that isEarly from BaseUtilClass is inlined into the feature
@@ -70,7 +71,7 @@
assertEquals(processResult.stdout, StringUtils.lines("42"));
}
- @NeverMerge
+ @NoVerticalClassMerging
public abstract static class BaseSuperClass implements RunInterface {
@Override
public void run() {
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/SplitterTestBase.java b/src/test/java/com/android/tools/r8/dexsplitter/SplitterTestBase.java
index 816ed12..c41a1d1 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/SplitterTestBase.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/SplitterTestBase.java
@@ -1,6 +1,5 @@
package com.android.tools.r8.dexsplitter;
-import static junit.framework.TestCase.assertTrue;
import static junit.framework.TestCase.fail;
import static org.junit.Assume.assumeTrue;
@@ -19,7 +18,6 @@
import com.android.tools.r8.ToolHelper.ProcessResult;
import com.android.tools.r8.dexsplitter.DexSplitter.Options;
import com.android.tools.r8.utils.ArchiveResourceProvider;
-import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.Pair;
import com.android.tools.r8.utils.ThrowingConsumer;
import com.android.tools.r8.utils.ZipUtils;
@@ -35,7 +33,6 @@
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
-import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;
@@ -53,7 +50,7 @@
Path outputPath,
TemporaryFolder temp,
Collection<Class<?>> classes) {
- addConsumers(builder, outputPath, temp, null, true, classes);
+ addConsumers(builder, outputPath, temp, null, classes);
return builder.build();
}
@@ -62,9 +59,7 @@
Path outputPath,
TemporaryFolder temp,
Collection<Pair<String, String>> nonJavaResources,
- boolean ensureClassesInOutput,
Collection<Class<?>> classes) {
- List<String> classNames = classes.stream().map(Class::getName).collect(Collectors.toList());
Path featureJar;
try {
featureJar = temp.newFolder().toPath().resolve("feature.jar");
@@ -109,26 +104,18 @@
ByteDataView data,
Set<String> descriptors,
DiagnosticsHandler handler) {
- if (ensureClassesInOutput) {
- for (String descriptor : descriptors) {
- assertTrue(
- classNames.contains(DescriptorUtils.descriptorToJavaType(descriptor)));
- }
- }
super.accept(fileIndex, data, descriptors, handler);
}
});
}
- static FeatureSplit splitWithNonJavaFile(
+ public static FeatureSplit splitWithNonJavaFile(
FeatureSplit.Builder builder,
Path outputPath,
TemporaryFolder temp,
Collection<Pair<String, String>> nonJavaFiles,
- boolean ensureClassesInOutput,
Class<?>... classes) {
- addConsumers(
- builder, outputPath, temp, nonJavaFiles, ensureClassesInOutput, Arrays.asList(classes));
+ addConsumers(builder, outputPath, temp, nonJavaFiles, Arrays.asList(classes));
return builder.build();
}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/AnnotationEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/AnnotationEnumUnboxingTest.java
index 6483aee..20362c3 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/AnnotationEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/AnnotationEnumUnboxingTest.java
@@ -5,8 +5,8 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestParameters;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
@@ -51,7 +51,7 @@
.addKeepRuntimeVisibleAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
.allowDiagnosticInfoMessages()
.setMinApi(parameters.getApiLevel())
@@ -83,7 +83,7 @@
MyEnumArray[] myEnumArray();
}
- @NeverMerge
+ @NoVerticalClassMerging
@Retention(RetentionPolicy.RUNTIME)
@interface ClassAnnotation {}
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/ClInitSideEffectEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/ClInitSideEffectEnumUnboxingTest.java
index d6dda57..74ee98c 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/ClInitSideEffectEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/ClInitSideEffectEnumUnboxingTest.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
import java.util.List;
@@ -43,7 +43,7 @@
.addKeepMainRule(classToTest)
.addKeepRules(enumKeepRules.getKeepRules())
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoStaticClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
.allowDiagnosticInfoMessages()
@@ -69,7 +69,7 @@
}
@NeverClassInline
- @NeverMerge
+ @NoStaticClassMerging
static class OtherClass {
static {
Switch.otherClassInit = true;
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingEnumUnboxingTest.java
index d1e5b4a..e9a7e5d 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingEnumUnboxingTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.enumunboxing.examplelib1.JavaLibrary1;
-import com.android.tools.r8.ir.optimize.enums.EnumUnboxingRewriter;
+import com.android.tools.r8.ir.optimize.enums.UnboxedEnumMemberRelocator;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -93,7 +93,7 @@
.anyMatch(
c ->
c.getOriginalName()
- .contains(EnumUnboxingRewriter.ENUM_UNBOXING_UTILITY_CLASS_NAME)));
+ .contains(UnboxedEnumMemberRelocator.ENUM_UNBOXING_UTILITY_CLASS_SUFFIX)));
}
static class App {
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingMergeEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingMergeEnumUnboxingTest.java
index 49fc118..227ce07 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingMergeEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/DoubleProcessingMergeEnumUnboxingTest.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.enumunboxing.examplelib1.JavaLibrary1;
import com.android.tools.r8.enumunboxing.examplelib2.JavaLibrary2;
-import com.android.tools.r8.ir.optimize.enums.EnumUnboxingRewriter;
+import com.android.tools.r8.ir.optimize.enums.UnboxedEnumMemberRelocator;
import com.android.tools.r8.references.Reference;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -97,7 +97,7 @@
.anyMatch(
c ->
c.getOriginalName()
- .contains(EnumUnboxingRewriter.ENUM_UNBOXING_UTILITY_CLASS_NAME)));
+ .contains(UnboxedEnumMemberRelocator.ENUM_UNBOXING_UTILITY_CLASS_SUFFIX)));
}
static class App {
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/InterfaceEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/InterfaceEnumUnboxingTest.java
index fba8006..7311ab2 100644
--- a/src/test/java/com/android/tools/r8/enumunboxing/InterfaceEnumUnboxingTest.java
+++ b/src/test/java/com/android/tools/r8/enumunboxing/InterfaceEnumUnboxingTest.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestParameters;
@@ -55,7 +55,7 @@
.addKeepMainRules(SUCCESSES)
.addKeepMainRules(FAILURES)
.noMinification()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.addKeepRules(enumKeepRules.getKeepRules())
@@ -106,7 +106,7 @@
C
}
- @NeverMerge
+ @NoVerticalClassMerging
interface Itf {}
}
@@ -124,7 +124,7 @@
C
}
- @NeverMerge
+ @NoVerticalClassMerging
interface Itf {
@NeverInline
default int ordinal() {
@@ -153,7 +153,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface Itf {
@NeverInline
default int method() {
@@ -176,7 +176,7 @@
C
}
- @NeverMerge
+ @NoVerticalClassMerging
interface Itf {
@NeverInline
default int method() {
@@ -205,7 +205,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface Itf {
int method();
}
@@ -225,7 +225,7 @@
C
}
- @NeverMerge
+ @NoVerticalClassMerging
interface Itf {
@NeverInline
default int method() {
@@ -259,7 +259,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface Itf {
@NeverInline
default int method() {
diff --git a/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java b/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
index 9848767..d191976 100644
--- a/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
+++ b/src/test/java/com/android/tools/r8/graph/MissingClassThrowingTest.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -23,10 +23,10 @@
@RunWith(Parameterized.class)
public class MissingClassThrowingTest extends TestBase {
- @NeverMerge
+ @NoStaticClassMerging
public static class MissingException extends Exception {}
- @NeverMerge
+ @NoStaticClassMerging
public static class Program {
public static final String EXPECTED_OUTPUT = "Hello world!";
@@ -72,11 +72,9 @@
.noMinification()
.noTreeShaking()
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoStaticClassMergingAnnotations()
.debug()
- .addKeepRules(
- "-keep class ** { *; }",
- "-keepattributes *")
+ .addKeepRules("-keep class ** { *; }", "-keepattributes *")
.compile()
.addRunClasspathClasses(MissingException.class)
.run(parameters.getRuntime(), Program.class)
diff --git a/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java b/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
index 090844e..4be7975 100644
--- a/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/graph/invokestatic/InvokeStaticOnInterfaceTest.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -64,7 +64,7 @@
.addProgramClasses(I.class)
.addProgramClassFileData(getClassWithTransformedInvoked())
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addKeepMainRule(Main.class)
.run(parameters.getRuntime(), Main.class);
}
@@ -77,7 +77,7 @@
.addProgramClasses(I.class)
.addProgramClassFileData(getClassWithTransformedInvoked())
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addOptionsModification(o -> o.testing.allowInvokeErrors = true)
.addKeepMainRule(Main.class)
.run(parameters.getRuntime(), Main.class);
@@ -104,7 +104,7 @@
.transform();
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/sideeffect/PutObjectWithFinalizeTest.java b/src/test/java/com/android/tools/r8/ir/analysis/sideeffect/PutObjectWithFinalizeTest.java
index c4d321a..dbbf99a 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/sideeffect/PutObjectWithFinalizeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/sideeffect/PutObjectWithFinalizeTest.java
@@ -10,7 +10,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -47,7 +47,7 @@
// The class staticizer does not consider the finalize() method.
.addOptionsModification(options -> options.enableClassStaticizer = false)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(
@@ -136,7 +136,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@Override
diff --git a/src/test/java/com/android/tools/r8/ir/analysis/type/MissingClassesJoinTest.java b/src/test/java/com/android/tools/r8/ir/analysis/type/MissingClassesJoinTest.java
index f46650f..6d3c6cb 100644
--- a/src/test/java/com/android/tools/r8/ir/analysis/type/MissingClassesJoinTest.java
+++ b/src/test/java/com/android/tools/r8/ir/analysis/type/MissingClassesJoinTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.D8TestCompileResult;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -70,7 +70,7 @@
.addKeepAllClassesRule()
.addOptionsModification(options -> options.testing.allowTypeErrors = allowTypeErrors)
.allowDiagnosticWarningMessages()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compileWithExpectedDiagnostics(
diagnostics -> {
@@ -133,7 +133,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
abstract static class A {}
static class ASub1 extends A {}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/AlwaysThrowNullTest.java b/src/test/java/com/android/tools/r8/ir/optimize/AlwaysThrowNullTest.java
index 0eb5fab..684b669 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/AlwaysThrowNullTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/AlwaysThrowNullTest.java
@@ -11,8 +11,8 @@
import com.android.tools.r8.D8TestRunResult;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.SingleTestRunResult;
import com.android.tools.r8.TestBase;
@@ -31,7 +31,7 @@
import org.junit.runners.Parameterized;
class AlwaysThrowNullTestClass {
- @NeverMerge
+ @NoVerticalClassMerging
static class Base {
Object dead;
@@ -239,7 +239,7 @@
R8TestRunResult result =
testForR8(parameters.getBackend())
.addProgramClassesAndInnerClasses(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableInliningAnnotations()
.enableMemberValuePropagationAnnotations()
.addKeepMainRule(MAIN)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/DefaultInterfaceIssue143628636Test.java b/src/test/java/com/android/tools/r8/ir/optimize/DefaultInterfaceIssue143628636Test.java
index 94de4ba..50fbd54 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/DefaultInterfaceIssue143628636Test.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/DefaultInterfaceIssue143628636Test.java
@@ -5,7 +5,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -43,7 +43,7 @@
testForR8(parameters.getBackend())
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addInnerClasses(DefaultInterfaceIssue143628636Test.class)
.addKeepMainRule(TestClass.class)
.addKeepClassRules(I.class)
@@ -52,7 +52,7 @@
.assertSuccessWithOutputLines("2", "5");
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
public interface A {
@@ -76,7 +76,7 @@
// Make sure this class and the call to h() are never eliminated. It is the *partial* info
// propagated from h() to f() that results in incorrect call-site optimization info.
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
public static class B implements A {
public final int x;
@@ -99,7 +99,7 @@
// Make sure this class and the call to h() are never eliminated. It is the *missing* info
// propagated from h() to f() that results in incorrect call-site optimization info.
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
public static class C implements I {
public final I i;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
index 626f771..964848a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/NonNullParamTest.java
@@ -226,7 +226,7 @@
.addOptionsModification(this::disableDevirtualization)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations());
+ .enableNoVerticalClassMergingAnnotations());
ClassSubject mainSubject = inspector.clazz(NonNullParamAfterInvokeInterface.class);
assertThat(mainSubject, isPresent());
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/HashCodeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/HashCodeTest.java
index 0c158b9..a36a63c 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/HashCodeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/HashCodeTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize.callsites;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -32,10 +32,11 @@
testForR8(parameters.getBackend())
.addInnerClasses(HashCodeTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .enableNoVerticalClassMergingAnnotations()
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("10");
@@ -55,7 +56,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@Override
public int hashCode() {
@@ -63,7 +64,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class B extends A {
@Override
public int hashCode() {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
index 2edbb0b..d6bcd2b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeInterfaceWithRefinedReceiverTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeInterfaceWithRefinedReceiverTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -108,7 +108,7 @@
void m(Object arg);
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
static class B implements I {
@NeverInline
@@ -149,7 +149,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
static class C implements I {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
index e36941d..43f777d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/InvokeVirtualWithRefinedReceiverTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeVirtualWithRefinedReceiverTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -105,7 +105,7 @@
abstract void m(Object arg);
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
static class B extends A {
@NeverInline
@@ -146,7 +146,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
static class C extends A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java
index fb3bc2e..429b5a2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/PropagationFromSiblingTest.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -36,7 +36,7 @@
.addKeepMainRule(TestClass.class)
.addOptionsModification(options -> options.enableUnusedInterfaceRemoval = false)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -66,7 +66,7 @@
interface J extends I {}
- @NeverMerge
+ @NoVerticalClassMerging
static class A implements I {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
index 75dd8a8..7c2eeee 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeInterfaceNegativeTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeInterfaceNegativeTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -80,7 +80,7 @@
assertTrue(a_m.streamInstructions().anyMatch(InstructionSubject::isIf));
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
void m(String arg);
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
index 3ae302a..7be71b2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualNegativeTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeVirtualNegativeTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -91,7 +91,7 @@
assertTrue(a_m.streamInstructions().anyMatch(InstructionSubject::isIf));
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
index 91d181e..5b3b309 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/constants/InvokeVirtualPositiveTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -45,7 +45,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeVirtualPositiveTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -92,7 +92,7 @@
assertTrue(b_m.streamInstructions().anyMatch(InstructionSubject::isIf));
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
index e131be5..51175f8 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeDirectPositiveTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeDirectPositiveTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -87,8 +87,9 @@
assertTrue(test.streamInstructions().noneMatch(InstructionSubject::isIf));
}
- @NeverMerge
+ @NoVerticalClassMerging
static class Base {}
+
static class Sub1 extends Base {}
static class Sub2 extends Base {}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
index 4b4c534..31e6779 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfaceNegativeTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeInterfaceNegativeTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -96,7 +96,7 @@
static class Sub1 extends Base {}
static class Sub2 extends Base {}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
void m(Base arg);
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
index bda0a3a..4091161 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeInterfacePositiveTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeInterfacePositiveTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -97,8 +97,9 @@
assertTrue(b_m.streamInstructions().anyMatch(InstructionSubject::isIf));
}
- @NeverMerge
+ @NoVerticalClassMerging
static class Base {}
+
static class Sub1 extends Base {}
static class Sub2 extends Base {}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java
index 6ea0888..ff19f58 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeStaticPositiveTest.java
@@ -8,7 +8,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -43,11 +43,12 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeStaticPositiveTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableInliningAnnotations()
- .addOptionsModification(o -> {
- o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
- })
+ .addOptionsModification(
+ o -> {
+ o.testing.callSiteOptimizationInfoInspector = this::callSiteOptimizationInfoInspect;
+ })
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MAIN)
.assertSuccessWithOutputLines("Sub1")
@@ -81,8 +82,9 @@
assertTrue(test.streamInstructions().noneMatch(InstructionSubject::isIf));
}
- @NeverMerge
+ @NoVerticalClassMerging
static class Base {}
+
static class Sub1 extends Base {}
static class Sub2 extends Base {}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
index 51145b2..39bfa4c 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualNegativeTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeVirtualNegativeTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -104,7 +104,7 @@
static class Sub1 extends Base {}
static class Sub2 extends Base {}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
index 8c17c3a..2595df5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/dynamicupperboundtype/InvokeVirtualPositiveTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeVirtualPositiveTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -95,12 +95,13 @@
assertTrue(b_m.streamInstructions().noneMatch(InstructionSubject::isIf));
}
- @NeverMerge
+ @NoVerticalClassMerging
static class Base {}
+
static class Sub1 extends Base {}
static class Sub2 extends Base {}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
index 79a49e0..bc9f10c 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeInterfaceNegativeTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeInterfaceNegativeTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -84,7 +84,7 @@
assertTrue(a_m.streamInstructions().anyMatch(InstructionSubject::isIf));
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
void m(Object arg);
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java
index d2181d5..f46869d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualCascadeTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -41,7 +41,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeVirtualCascadeTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
@@ -68,7 +68,7 @@
assertTrue(b_m.streamInstructions().anyMatch(InstructionSubject::isIf));
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
index 26bb65e..544cf86 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualNegativeTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeVirtualNegativeTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -92,7 +92,7 @@
assertTrue(a_m.streamInstructions().anyMatch(InstructionSubject::isIf));
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
index 00601a9..2cff135 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/callsites/nullability/InvokeVirtualPositiveTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(InvokeVirtualPositiveTest.class)
.addKeepMainRule(MAIN)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addOptionsModification(
@@ -91,7 +91,7 @@
assertTrue(b_m.streamInstructions().anyMatch(InstructionSubject::isIf));
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/UnresolvableLibraryConstClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/UnresolvableLibraryConstClassTest.java
index 47ae6be..2765bb2 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/UnresolvableLibraryConstClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/canonicalization/UnresolvableLibraryConstClassTest.java
@@ -8,7 +8,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeTrue;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -26,9 +26,8 @@
class LibraryClass {
}
-@NeverMerge
-class ProgramClass1 extends LibraryClass {
-}
+@NoVerticalClassMerging
+class ProgramClass1 extends LibraryClass {}
class ProgramSubClass extends ProgramClass1 {
}
@@ -114,7 +113,7 @@
.addProgramClasses(ProgramClass1.class, ProgramClass2.class, ProgramSubClass.class, MAIN)
.addKeepMainRule(MAIN)
.noMinification()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addOptionsModification(InternalOptions::disableNameReflectionOptimization)
.setMinApi(parameters.getRuntime())
.compile()
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/BuilderWithInheritanceTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/BuilderWithInheritanceTest.java
index 73d694e..d158c7d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/BuilderWithInheritanceTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/BuilderWithInheritanceTest.java
@@ -9,7 +9,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -41,7 +41,7 @@
.addInnerClasses(BuilderWithInheritanceTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput("42")
@@ -70,7 +70,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class BuilderBase {
protected int f;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/BuilderWithMethodOnParentClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/BuilderWithMethodOnParentClassTest.java
index 7076755..a8098cb 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/BuilderWithMethodOnParentClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/BuilderWithMethodOnParentClassTest.java
@@ -9,8 +9,8 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -40,7 +40,7 @@
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
.enableMemberValuePropagationAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
@@ -60,7 +60,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class BuilderBase {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithAccessibleStaticGetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithAccessibleStaticGetTest.java
index 596c9e5..e603587 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithAccessibleStaticGetTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithAccessibleStaticGetTest.java
@@ -9,7 +9,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -38,7 +38,7 @@
.addInnerClasses(ClassInlineInstanceInitializerWithAccessibleStaticGetTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
@@ -61,7 +61,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class CandidateBase {
final String f;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithCheckCastTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithCheckCastTest.java
index c0f45d4..29a3cb6 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithCheckCastTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithCheckCastTest.java
@@ -9,7 +9,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -38,7 +38,7 @@
.addInnerClasses(ClassInlineInstanceInitializerWithCheckCastTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
@@ -59,7 +59,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class CandidateBase {
final String f;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithIfTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithIfTest.java
index 912374d..a39dd98 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithIfTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithIfTest.java
@@ -9,7 +9,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -38,7 +38,7 @@
.addInnerClasses(ClassInlineInstanceInitializerWithIfTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
@@ -59,7 +59,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class CandidateBase {
final String f;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithInaccessibleStaticGetTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithInaccessibleStaticGetTest.java
index 34e9d5d..26e44d5 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithInaccessibleStaticGetTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithInaccessibleStaticGetTest.java
@@ -41,7 +41,7 @@
ClassInlineInstanceInitializerWithInaccessibleStaticGetTestClasses.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoStaticClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithIndirectEscapingReceiverTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithIndirectEscapingReceiverTest.java
index c86e0fc..d1e2e54 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithIndirectEscapingReceiverTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithIndirectEscapingReceiverTest.java
@@ -8,8 +8,8 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -39,7 +39,7 @@
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
.enableMemberValuePropagationAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
@@ -59,7 +59,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class CandidateBase {
CandidateBase() {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithInstanceOfTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithInstanceOfTest.java
index 43e2998..a0429d1 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithInstanceOfTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineInstanceInitializerWithInstanceOfTest.java
@@ -9,7 +9,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -38,7 +38,7 @@
.addInnerClasses(ClassInlineInstanceInitializerWithInstanceOfTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
@@ -59,7 +59,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class CandidateBase {
final boolean f;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineKeepMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineKeepMethodTest.java
index 4ccc742..16aac95 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineKeepMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlineKeepMethodTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -32,7 +32,7 @@
private final TestParameters parameters;
private static final String EXPECTED_OUTPUT = "Hello world";
- @NeverMerge
+ @NoVerticalClassMerging
public static class ShouldBeKept {
@NeverInline
@@ -61,15 +61,16 @@
@Test
public void testIsKeptWithName()
throws ExecutionException, CompilationFailedException, IOException {
- CodeInspector inspector = testForR8(parameters.getBackend())
- .addInnerClasses(ClassInlineKeepMethodTest.class)
- .addKeepMainRule(Keeper.class)
- .addKeepClassAndMembersRules(ShouldBeKept.class)
- .enableInliningAnnotations()
- .enableMergeAnnotations()
- .run(parameters.getRuntime(), Keeper.class)
- .assertSuccessWithOutput(EXPECTED_OUTPUT)
- .inspector();
+ CodeInspector inspector =
+ testForR8(parameters.getBackend())
+ .addInnerClasses(ClassInlineKeepMethodTest.class)
+ .addKeepMainRule(Keeper.class)
+ .addKeepClassAndMembersRules(ShouldBeKept.class)
+ .enableInliningAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
+ .run(parameters.getRuntime(), Keeper.class)
+ .assertSuccessWithOutput(EXPECTED_OUTPUT)
+ .inspector();
ClassSubject clazz = inspector.clazz(Keeper.class);
assertThat(clazz, isPresent());
MethodSubject main = clazz.uniqueMethodWithName("main");
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerWithSimpleSuperTypeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerWithSimpleSuperTypeTest.java
index b8b159c..13a5fcc 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerWithSimpleSuperTypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInlinerWithSimpleSuperTypeTest.java
@@ -9,7 +9,7 @@
import static org.junit.Assert.assertNotEquals;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
@@ -48,7 +48,7 @@
.addKeepMainRule(TestClass.class)
.addOptionsModification(options -> options.enableClassInlining = enableClassInlining)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::verifyCandidateIsClassInlined)
@@ -83,10 +83,10 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {}
- @NeverMerge
+ @NoVerticalClassMerging
static class B extends A {}
static class C extends B {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java
index bd87a92..e0bd65e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningOracleTest.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.KeepUnusedArguments;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
@@ -50,7 +50,7 @@
enableInvokeSuperToInvokeVirtualRewriting)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableUnusedArgumentAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -78,7 +78,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class HelperBase {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningWithImpreciseReceiverTypeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningWithImpreciseReceiverTypeTest.java
index cfdfcda..973ae87 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningWithImpreciseReceiverTypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/ClassInliningWithImpreciseReceiverTypeTest.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.optimize.classinliner;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -33,7 +33,7 @@
.addInnerClasses(ClassInliningWithImpreciseReceiverTypeTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.run(parameters.getRuntime(), TestClass.class)
@@ -51,7 +51,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
abstract static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/EscapeFromParentConstructorTest.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/EscapeFromParentConstructorTest.java
index 2062667..6f5ab71 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/EscapeFromParentConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/EscapeFromParentConstructorTest.java
@@ -8,7 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -38,7 +38,7 @@
.addInnerClasses(EscapeFromParentConstructorTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
@@ -60,7 +60,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class BuilderBase {
String greeting;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/testclasses/ClassInlineInstanceInitializerWithInaccessibleStaticGetTestClasses.java b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/testclasses/ClassInlineInstanceInitializerWithInaccessibleStaticGetTestClasses.java
index 50eeac4..cc0734b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/classinliner/testclasses/ClassInlineInstanceInitializerWithInaccessibleStaticGetTestClasses.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/classinliner/testclasses/ClassInlineInstanceInitializerWithInaccessibleStaticGetTestClasses.java
@@ -4,11 +4,11 @@
package com.android.tools.r8.ir.optimize.classinliner.testclasses;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
public class ClassInlineInstanceInitializerWithInaccessibleStaticGetTestClasses {
- @NeverMerge
+ @NoStaticClassMerging
public static class CandidateBase {
public final String f;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/DevirtualizerNonNullRewritingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/DevirtualizerNonNullRewritingTest.java
index 61d5cf3..28a973c 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/DevirtualizerNonNullRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/DevirtualizerNonNullRewritingTest.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.optimize.devirtualize;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -46,7 +46,7 @@
.addInnerClasses(DevirtualizerNonNullRewritingTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED_OUTPUT);
@@ -78,14 +78,14 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface Interface {
@NeverInline
void method();
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InterfaceRenewalInLoopDebugTest.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InterfaceRenewalInLoopDebugTest.java
index 80a6d8d..d4e3985 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InterfaceRenewalInLoopDebugTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InterfaceRenewalInLoopDebugTest.java
@@ -3,7 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize.devirtualize;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import java.util.ArrayList;
import java.util.List;
@@ -11,7 +11,7 @@
void foo();
}
-@NeverMerge
+@NoVerticalClassMerging
class OneUniqueImplementer implements TestInterface {
String boo;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InvokeSuperToInvokeVirtualTest.java b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InvokeSuperToInvokeVirtualTest.java
index a85906b..98628aa 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InvokeSuperToInvokeVirtualTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/devirtualize/InvokeSuperToInvokeVirtualTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -42,7 +42,7 @@
.addInnerClasses(InvokeSuperToInvokeVirtualTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -89,7 +89,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningInvokeSuperTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningInvokeSuperTest.java
index 9bc40d7..47dc21e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningInvokeSuperTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/DoubleInliningInvokeSuperTest.java
@@ -5,7 +5,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -39,14 +39,14 @@
.addKeepRules("-keepclassmembers class * { void fooCaller(...); }")
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getRuntime())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(EXPECTED);
}
@NeverClassInline
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
int x;
@NeverInline
@@ -57,7 +57,7 @@
}
@NeverClassInline
- @NeverMerge
+ @NoVerticalClassMerging
static class B extends A {
// B#foo is invoked twice by other wrappers in the same class.
@Override
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineNonReboundFieldTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineNonReboundFieldTest.java
index d0d52ec..b2fe085 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineNonReboundFieldTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InlineNonReboundFieldTest.java
@@ -28,7 +28,7 @@
TestClass.class, Greeter.class, Greeting.class, Greeting.getGreetingBase())
.addKeepMainRule(TestClass.class)
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.run(TestClass.class)
.assertSuccessWithOutput(expectedOutput)
.inspector();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningFromCurrentClassTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningFromCurrentClassTest.java
index a7aa579..f70aebe 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningFromCurrentClassTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningFromCurrentClassTest.java
@@ -10,7 +10,7 @@
import static org.hamcrest.core.IsNot.not;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -54,7 +54,7 @@
.addInnerClasses(InliningFromCurrentClassTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(expectedOutput)
@@ -91,7 +91,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
static {
@@ -103,7 +103,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class B extends A {
static {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningIntoVisibilityBridgeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningIntoVisibilityBridgeTest.java
index ec3c011..a3b0c4a 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningIntoVisibilityBridgeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningIntoVisibilityBridgeTest.java
@@ -51,7 +51,7 @@
neverInline
? ("-neverinline class " + getClassA().getTypeName() + " { method(); }")
: "")
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableProguardTestOptions()
.compile()
.run(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningWithClassInitializerTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningWithClassInitializerTest.java
index c8bb388..ab412be 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningWithClassInitializerTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/InliningWithClassInitializerTest.java
@@ -10,7 +10,7 @@
import static org.hamcrest.core.IsNot.not;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -31,7 +31,7 @@
.addInnerClasses(InliningWithClassInitializerTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.run(TestClass.class)
.assertSuccessWithOutput(expectedOutput)
.inspector();
@@ -61,7 +61,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
static {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
index 0e4627b..177353f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/interfacemethods/InlineDefaultInterfaceMethodTest.java
@@ -7,7 +7,7 @@
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -42,7 +42,7 @@
.addKeepMainRule(TestClass.class)
.setMinApi(parameters.getApiLevel())
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.noMinification()
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(expectedOutput)
@@ -59,7 +59,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
default void hello() {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/testclasses/Greeting.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/testclasses/Greeting.java
index 636b0ac..717c09f 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/testclasses/Greeting.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/testclasses/Greeting.java
@@ -4,9 +4,9 @@
package com.android.tools.r8.ir.optimize.inliner.testclasses;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
-@NeverMerge
+@NoVerticalClassMerging
public class Greeting extends GreetingBase {
public static Class<?> getGreetingBase() {
@@ -14,7 +14,7 @@
}
}
-@NeverMerge
+@NoVerticalClassMerging
class GreetingBase {
protected String greeting;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/inliner/testclasses/InliningIntoVisibilityBridgeTestClasses.java b/src/test/java/com/android/tools/r8/ir/optimize/inliner/testclasses/InliningIntoVisibilityBridgeTestClasses.java
index afa71fc..c8c60ae 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/inliner/testclasses/InliningIntoVisibilityBridgeTestClasses.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/inliner/testclasses/InliningIntoVisibilityBridgeTestClasses.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.ir.optimize.inliner.testclasses;
import com.android.tools.r8.ForceInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
public class InliningIntoVisibilityBridgeTestClasses {
@@ -13,7 +13,7 @@
return InliningIntoVisibilityBridgeTestClassA.class;
}
- @NeverMerge
+ @NoVerticalClassMerging
static class InliningIntoVisibilityBridgeTestClassA {
@ForceInline
@@ -22,7 +22,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public static class InliningIntoVisibilityBridgeTestClassB
extends InliningIntoVisibilityBridgeTestClassA {}
}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/lambda/LambdaMethodInliningTest.java b/src/test/java/com/android/tools/r8/ir/optimize/lambda/LambdaMethodInliningTest.java
index c90173e..8bdea50 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/lambda/LambdaMethodInliningTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/lambda/LambdaMethodInliningTest.java
@@ -9,7 +9,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -41,7 +41,7 @@
.addInnerClasses(LambdaMethodInliningTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addOptionsModification(options -> options.enableClassInlining = false)
.setMinApi(parameters.getApiLevel())
.compile()
@@ -108,7 +108,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface ImplementedByClass {
void m();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StaticFieldWithRefinedTypeTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StaticFieldWithRefinedTypeTest.java
index 7cf1f42..8473c67 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StaticFieldWithRefinedTypeTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/StaticFieldWithRefinedTypeTest.java
@@ -9,7 +9,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -42,7 +42,7 @@
.addInnerClasses(StaticFieldWithRefinedTypeTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
.inspect(this::verifyMainIsEmpty)
@@ -75,7 +75,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {}
static class B extends A {}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/fields/FieldInitializedByNonConstantArgumentInSuperConstructorTest.java b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/fields/FieldInitializedByNonConstantArgumentInSuperConstructorTest.java
index a59e9a9..9ffd5ee 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/fields/FieldInitializedByNonConstantArgumentInSuperConstructorTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/membervaluepropagation/fields/FieldInitializedByNonConstantArgumentInSuperConstructorTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -40,7 +40,7 @@
.addInnerClasses(FieldInitializedByNonConstantArgumentInSuperConstructorTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -82,7 +82,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
int x;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamInterface.java b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamInterface.java
index e20992e..f4ee88c 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamInterface.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/nonnull/NonNullParamInterface.java
@@ -3,9 +3,9 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.optimize.nonnull;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
-@NeverMerge
+@NoVerticalClassMerging
public interface NonNullParamInterface {
int sum(NotPinnedClass arg1, NotPinnedClass arg2);
}
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 5691577..66c42e8 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
@@ -10,7 +10,7 @@
import com.android.tools.r8.AssumeMayHaveSideEffects;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -63,7 +63,7 @@
testForR8(parameters.getBackend())
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableSideEffectAnnotations()
.addInnerClasses(B133215941.class)
.addKeepMainRule(TestClass.class)
@@ -84,12 +84,12 @@
.assertSuccessWithOutput(expectedOutput);
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface Iface {
void ifaceMethod();
}
- @NeverMerge
+ @NoVerticalClassMerging
public static class TestClassSuper {
@AssumeMayHaveSideEffects
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/staticizer/SynchronizedCompanionMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/SynchronizedCompanionMethodTest.java
new file mode 100644
index 0000000..8df91f6
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/staticizer/SynchronizedCompanionMethodTest.java
@@ -0,0 +1,85 @@
+// Copyright (c) 2020, 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.ir.optimize.staticizer;
+
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.NeverClassInline;
+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.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class SynchronizedCompanionMethodTest extends TestBase {
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public SynchronizedCompanionMethodTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(TestClass.class)
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject testClassSubject = inspector.clazz(TestClass.class);
+ assertThat(testClassSubject, isPresent());
+ assertEquals(
+ 1,
+ testClassSubject
+ .allMethods(method -> method.isStatic() && !method.isClassInitializer())
+ .size());
+
+ ClassSubject companionClassSubject = inspector.clazz(Companion.class);
+ assertThat(companionClassSubject, isPresent());
+ assertEquals(
+ 1,
+ companionClassSubject
+ .allMethods(method -> !method.isStatic() && method.isSynchronized())
+ .size());
+ }
+
+ static class TestClass {
+
+ static final Companion companion = new Companion();
+
+ public static void main(String[] args) {
+ companion.greet();
+ }
+ }
+
+ @NeverClassInline
+ static class Companion {
+
+ @NeverInline
+ public synchronized void greet() {
+ System.out.println("Hello world!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InterfaceMethodTest.java
index 6ca0f7c..9fd146d 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/InterfaceMethodTest.java
@@ -8,7 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.StringUtils;
@@ -47,7 +47,7 @@
.addInnerClasses(InterfaceMethodTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.run(TestClass.class)
.assertSuccessWithOutput(expectedOutput)
.inspector();
@@ -76,7 +76,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
Uninstantiated m();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java
index b5752cc..7890640 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/NestedInterfaceMethodTest.java
@@ -8,7 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -49,7 +49,7 @@
.addInnerClasses(NestedInterfaceMethodTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addOptionsModification(
options -> {
options.enableDevirtualization = false;
@@ -82,13 +82,13 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
Uninstantiated m();
}
- @NeverMerge
+ @NoVerticalClassMerging
interface J extends I {}
static class A implements J {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java
index 7423491..167c17b 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/ParameterRewritingTest.java
@@ -9,7 +9,7 @@
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.graph.DexMethod;
@@ -53,7 +53,7 @@
.addInnerClasses(ParameterRewritingTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoStaticClassMergingAnnotations()
.addKeepRules("-dontobfuscate")
.addOptionsModification(options -> options.enableClassInlining = false)
.run(TestClass.class)
@@ -114,10 +114,10 @@
}
}
- @NeverMerge
+ @NoStaticClassMerging
static class Uninstantiated {}
- @NeverMerge
+ @NoStaticClassMerging
static class Factory {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
index a4afbb1..7d3eb83 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/uninstantiatedtypes/VoidReturnTypeRewritingTest.java
@@ -8,7 +8,8 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.utils.StringUtils;
@@ -50,7 +51,8 @@
.addInnerClasses(VoidReturnTypeRewritingTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
+ .enableNoStaticClassMergingAnnotations()
.addKeepRules("-dontobfuscate")
.addOptionsModification(options -> options.enableClassInlining = false)
.run(TestClass.class)
@@ -102,13 +104,14 @@
}
}
- @NeverMerge
+ @NoStaticClassMerging
+ @NoVerticalClassMerging
static class Uninstantiated {}
- @NeverMerge
+ @NoVerticalClassMerging
static class SubUninstantiated extends Uninstantiated {}
- @NeverMerge
+ @NoVerticalClassMerging
static class Factory {
@NeverInline
@@ -124,7 +127,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class SubFactory extends Factory {
@Override
@@ -135,7 +138,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class SubSubFactory extends SubFactory {
@Override
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
index 461ec6b..7456d35 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentRemovalWithOverridingTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
@@ -48,7 +48,7 @@
.addKeepMainRule(TestClass.class)
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.minification(minification)
.setMinApi(parameters.getRuntime())
.compile()
@@ -75,7 +75,7 @@
}
@NeverClassInline
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
index 08d8c09..2c7fe55 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsCollisionTest.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
@@ -58,7 +58,7 @@
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.minification(minification)
.setMinApi(parameters.getRuntime())
.compile()
@@ -115,7 +115,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInMethodThatImplementsInterfaceMethodOnSubTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInMethodThatImplementsInterfaceMethodOnSubTest.java
index 9001472..9a4d4d0 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInMethodThatImplementsInterfaceMethodOnSubTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedarguments/UnusedArgumentsInMethodThatImplementsInterfaceMethodOnSubTest.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.ir.optimize.unusedarguments;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -32,7 +32,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(UnusedArgumentsInMethodThatImplementsInterfaceMethodOnSubTest.class)
.addKeepMainRule(TestClass.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutputLines("Hello from A", "Hello from C");
@@ -52,7 +52,7 @@
void method(Object o);
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
public void method(Object unused) {
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalTest.java
index 8b2c2a1..413937e 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceRemovalTest.java
@@ -9,7 +9,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -39,7 +39,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(UnusedInterfaceRemovalTest.class)
.addKeepMainRule(TestClass.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
@@ -77,13 +77,13 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
void foo();
}
- @NeverMerge
+ @NoVerticalClassMerging
interface J {
void bar();
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceWithDefaultMethodTest.java b/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceWithDefaultMethodTest.java
index 9a342e1..52131b3 100644
--- a/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceWithDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/ir/optimize/unusedinterfaces/UnusedInterfaceWithDefaultMethodTest.java
@@ -9,7 +9,7 @@
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -40,7 +40,7 @@
.addInnerClasses(UnusedInterfaceWithDefaultMethodTest.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
@@ -78,13 +78,13 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
void m();
}
- @NeverMerge
+ @NoVerticalClassMerging
interface J extends I {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
new file mode 100644
index 0000000..3b35a09
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/LambdaGroupGCLimitTest.java
@@ -0,0 +1,84 @@
+// Copyright (c) 2020, 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.kotlin.lambda.b159688129;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.R8FullTestBuilder;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
+import com.android.tools.r8.ToolHelper;
+import com.android.tools.r8.ToolHelper.ProcessResult;
+import com.android.tools.r8.utils.codeinspector.FoundClassSubject;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutionException;
+import java.util.stream.Collectors;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class LambdaGroupGCLimitTest extends TestBase {
+
+ private final TestParameters parameters;
+ private final int LAMBDA_HOLDER_LIMIT = 50;
+ private final int LAMBDAS_PER_CLASS_LIMIT = 100;
+
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withDexRuntimes().withAllApiLevels().build();
+ }
+
+ public LambdaGroupGCLimitTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testR8() throws ExecutionException, CompilationFailedException, IOException {
+ String PKG_NAME = LambdaGroupGCLimitTest.class.getPackage().getName();
+ R8FullTestBuilder testBuilder =
+ testForR8(parameters.getBackend())
+ .addProgramFiles(ToolHelper.getKotlinStdlibJar())
+ .setMinApi(parameters.getApiLevel())
+ .noMinification();
+ Path classFiles = temp.newFile("classes.jar").toPath();
+ List<byte[]> classFileData = new ArrayList<>();
+ for (int mainId = 0; mainId < LAMBDA_HOLDER_LIMIT; mainId++) {
+ classFileData.add(MainKtDump.dump(mainId, LAMBDAS_PER_CLASS_LIMIT));
+ for (int lambdaId = 0; lambdaId < LAMBDAS_PER_CLASS_LIMIT; lambdaId++) {
+ classFileData.add(MainKt$main$1Dump.dump(mainId, lambdaId));
+ }
+ testBuilder.addKeepClassAndMembersRules(PKG_NAME + ".MainKt" + mainId);
+ }
+ writeClassFileDataToJar(classFiles, classFileData);
+ R8TestCompileResult compileResult = testBuilder.addProgramFiles(classFiles).compile();
+ Path path = compileResult.writeToZip();
+ compileResult
+ .run(parameters.getRuntime(), PKG_NAME + ".MainKt0")
+ .assertSuccessWithOutputLines("3")
+ .inspect(
+ codeInspector -> {
+ final List<FoundClassSubject> lambdaGroups =
+ codeInspector.allClasses().stream()
+ .filter(c -> c.getFinalName().contains("LambdaGroup"))
+ .collect(Collectors.toList());
+ assertEquals(1, lambdaGroups.size());
+ });
+ Path oatFile = temp.newFile("out.oat").toPath();
+ ProcessResult processResult =
+ ToolHelper.runDex2OatRaw(path, oatFile, parameters.getRuntime().asDex().getVm());
+ assertEquals(0, processResult.exitCode);
+ assertThat(processResult.stderr, containsString("Method exceeds compiler instruction limit"));
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/Main.kt b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/Main.kt
new file mode 100644
index 0000000..0bbca3c
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/Main.kt
@@ -0,0 +1,16 @@
+// Copyright (c) 2020, 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.kotlin.lambda.b159688129
+
+import com.android.tools.r8.NeverInline
+
+fun main() {
+ run ({ arg -> println(arg)}, 3)
+}
+
+@NeverInline
+fun run(param: Function1<Int, Unit>, arg : Int) {
+ param.invoke(arg)
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/MainKt$main$1Dump.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/MainKt$main$1Dump.java
new file mode 100644
index 0000000..f9ead12
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/MainKt$main$1Dump.java
@@ -0,0 +1,160 @@
+// Copyright (c) 2020, 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.kotlin.lambda.b159688129;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+class MainKt$main$1Dump implements Opcodes {
+
+ public static byte[] dump(int mainId, int lambdaId) {
+
+ ClassWriter classWriter = new ClassWriter(0);
+ FieldVisitor fieldVisitor;
+ MethodVisitor methodVisitor;
+ AnnotationVisitor annotationVisitor0;
+
+ classWriter.visit(
+ V1_8,
+ ACC_FINAL | ACC_SUPER,
+ "com/android/tools/r8/kotlin/lambda/b159688129/MainKt" + mainId + "$main$" + lambdaId,
+ "Lkotlin/jvm/internal/Lambda;Lkotlin/jvm/functions/Function1<Ljava/lang/Integer;Lkotlin/Unit;>;",
+ "kotlin/jvm/internal/Lambda",
+ new String[] {"kotlin/jvm/functions/Function1"});
+
+ classWriter.visitOuterClass(
+ "com/android/tools/r8/kotlin/lambda/b159688129/MainKt" + mainId,
+ lambdaId > 0 ? "main" + lambdaId : "main",
+ "()V");
+
+ {
+ annotationVisitor0 = classWriter.visitAnnotation("Lkotlin/Metadata;", true);
+ annotationVisitor0.visit("mv", new int[] {1, 1, 16});
+ annotationVisitor0.visit("bv", new int[] {1, 0, 3});
+ annotationVisitor0.visit("k", new Integer(3));
+ {
+ AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("d1");
+ annotationVisitor1.visit(
+ null,
+ "\u0000\u000e\n"
+ + "\u0000\n"
+ + "\u0002\u0010\u0002\n"
+ + "\u0000\n"
+ + "\u0002\u0010\u0008\n"
+ + "\u0000\u0010\u0000\u001a\u00020\u00012\u0006\u0010\u0002\u001a\u00020\u0003H\n"
+ + "\u00a2\u0006\u0002\u0008\u0004");
+ annotationVisitor1.visitEnd();
+ }
+ {
+ AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("d2");
+ annotationVisitor1.visit(null, "<anonymous>");
+ annotationVisitor1.visit(null, "");
+ annotationVisitor1.visit(null, "arg");
+ annotationVisitor1.visit(null, "");
+ annotationVisitor1.visit(null, "invoke");
+ annotationVisitor1.visitEnd();
+ }
+ annotationVisitor0.visitEnd();
+ }
+ classWriter.visitInnerClass(
+ "com/android/tools/r8/kotlin/lambda/b159688129/MainKt" + mainId + "$main$" + lambdaId,
+ null,
+ null,
+ ACC_FINAL | ACC_STATIC);
+ {
+ fieldVisitor =
+ classWriter.visitField(
+ ACC_PUBLIC | ACC_FINAL | ACC_STATIC,
+ "INSTANCE",
+ "Lcom/android/tools/r8/kotlin/lambda/b159688129/MainKt"
+ + mainId
+ + "$main$"
+ + lambdaId
+ + ";",
+ null,
+ null);
+ fieldVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_BRIDGE | ACC_SYNTHETIC,
+ "invoke",
+ "(Ljava/lang/Object;)Ljava/lang/Object;",
+ null,
+ null);
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitVarInsn(ALOAD, 1);
+ methodVisitor.visitTypeInsn(CHECKCAST, "java/lang/Number");
+ methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Number", "intValue", "()I", false);
+ methodVisitor.visitMethodInsn(
+ INVOKEVIRTUAL,
+ "com/android/tools/r8/kotlin/lambda/b159688129/MainKt" + mainId + "$main$" + lambdaId,
+ "invoke",
+ "(I)V",
+ false);
+ methodVisitor.visitFieldInsn(GETSTATIC, "kotlin/Unit", "INSTANCE", "Lkotlin/Unit;");
+ methodVisitor.visitInsn(ARETURN);
+ methodVisitor.visitMaxs(2, 2);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor = classWriter.visitMethod(ACC_PUBLIC | ACC_FINAL, "invoke", "(I)V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitInsn(ICONST_0);
+ methodVisitor.visitVarInsn(ISTORE, 2);
+ methodVisitor.visitFieldInsn(GETSTATIC, "java/lang/System", "out", "Ljava/io/PrintStream;");
+ methodVisitor.visitVarInsn(ILOAD, 1);
+ methodVisitor.visitMethodInsn(INVOKEVIRTUAL, "java/io/PrintStream", "println", "(I)V", false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(2, 3);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor = classWriter.visitMethod(0, "<init>", "()V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitInsn(ICONST_1);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL, "kotlin/jvm/internal/Lambda", "<init>", "(I)V", false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(2, 1);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor = classWriter.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitTypeInsn(
+ NEW,
+ "com/android/tools/r8/kotlin/lambda/b159688129/MainKt" + mainId + "$main$" + lambdaId);
+ methodVisitor.visitInsn(DUP);
+ methodVisitor.visitMethodInsn(
+ INVOKESPECIAL,
+ "com/android/tools/r8/kotlin/lambda/b159688129/MainKt" + mainId + "$main$" + lambdaId,
+ "<init>",
+ "()V",
+ false);
+ methodVisitor.visitFieldInsn(
+ PUTSTATIC,
+ "com/android/tools/r8/kotlin/lambda/b159688129/MainKt" + mainId + "$main$" + lambdaId,
+ "INSTANCE",
+ "Lcom/android/tools/r8/kotlin/lambda/b159688129/MainKt"
+ + mainId
+ + "$main$"
+ + lambdaId
+ + ";");
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(2, 0);
+ methodVisitor.visitEnd();
+ }
+ classWriter.visitEnd();
+
+ return classWriter.toByteArray();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/MainKtDump.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/MainKtDump.java
new file mode 100644
index 0000000..7321fcb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/MainKtDump.java
@@ -0,0 +1,153 @@
+// Copyright (c) 2020, 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.kotlin.lambda.b159688129;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class MainKtDump implements Opcodes {
+
+ public static byte[] dump(int id, int numberOfLambdas) {
+
+ ClassWriter classWriter = new ClassWriter(0);
+ MethodVisitor methodVisitor;
+ AnnotationVisitor annotationVisitor0;
+
+ classWriter.visit(
+ V1_8,
+ ACC_PUBLIC | ACC_FINAL | ACC_SUPER,
+ "com/android/tools/r8/kotlin/lambda/b159688129/MainKt" + id,
+ null,
+ "java/lang/Object",
+ null);
+
+ {
+ annotationVisitor0 = classWriter.visitAnnotation("Lkotlin/Metadata;", true);
+ annotationVisitor0.visit("mv", new int[] {1, 1, 16});
+ annotationVisitor0.visit("bv", new int[] {1, 0, 3});
+ annotationVisitor0.visit("k", new Integer(2));
+ {
+ AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("d1");
+ annotationVisitor1.visit(
+ null,
+ "\u0000\u0016\n"
+ + "\u0000\n"
+ + "\u0002\u0010\u0002\n"
+ + "\u0002\u0008\u0002\n"
+ + "\u0002\u0018\u0002\n"
+ + "\u0002\u0010\u0008\n"
+ + "\u0002\u0008\u0002\u001a\u0006\u0010\u0000\u001a\u00020\u0001\u001a$\u0010\u0002\u001a\u00020\u00012\u0012\u0010\u0003\u001a\u000e\u0012\u0004\u0012\u00020\u0005\u0012\u0004\u0012\u00020\u00010\u00042\u0006\u0010\u0006\u001a\u00020\u0005H\u0007\u00a8\u0006\u0007");
+ annotationVisitor1.visitEnd();
+ }
+ {
+ AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("d2");
+ annotationVisitor1.visit(null, "main");
+ annotationVisitor1.visit(null, "");
+ annotationVisitor1.visit(null, "run");
+ annotationVisitor1.visit(null, "param");
+ annotationVisitor1.visit(null, "Lkotlin/Function1;");
+ annotationVisitor1.visit(null, "");
+ annotationVisitor1.visit(null, "arg");
+ annotationVisitor1.visit(null, "r8.main");
+ annotationVisitor1.visitEnd();
+ }
+ annotationVisitor0.visitEnd();
+ }
+ for (int lambdaId = 0; lambdaId < numberOfLambdas; lambdaId++) {
+ if (lambdaId > 0) {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_FINAL | ACC_STATIC, "main" + lambdaId, "()V", null, null);
+ } else {
+ methodVisitor =
+ classWriter.visitMethod(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, "main", "()V", null, null);
+ }
+ methodVisitor.visitCode();
+ methodVisitor.visitFieldInsn(
+ GETSTATIC,
+ "com/android/tools/r8/kotlin/lambda/b159688129/MainKt" + id + "$main$" + lambdaId,
+ "INSTANCE",
+ "Lcom/android/tools/r8/kotlin/lambda/b159688129/MainKt" + id + "$main$" + lambdaId + ";");
+ methodVisitor.visitTypeInsn(CHECKCAST, "kotlin/jvm/functions/Function1");
+ methodVisitor.visitInsn(ICONST_3);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "com/android/tools/r8/kotlin/lambda/b159688129/MainKt" + id,
+ "run",
+ "(Lkotlin/jvm/functions/Function1;I)V",
+ false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(2, 0);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC,
+ "main",
+ "([Ljava/lang/String;)V",
+ null,
+ null);
+ methodVisitor.visitCode();
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "com/android/tools/r8/kotlin/lambda/b159688129/MainKt" + id,
+ "main",
+ "()V",
+ false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(0, 1);
+ methodVisitor.visitEnd();
+ }
+ {
+ methodVisitor =
+ classWriter.visitMethod(
+ ACC_PUBLIC | ACC_FINAL | ACC_STATIC,
+ "run",
+ "(Lkotlin/jvm/functions/Function1;I)V",
+ "(Lkotlin/jvm/functions/Function1<-Ljava/lang/Integer;Lkotlin/Unit;>;I)V",
+ null);
+ {
+ annotationVisitor0 =
+ methodVisitor.visitAnnotation("Lcom/android/tools/r8/NeverInline;", true);
+ annotationVisitor0.visitEnd();
+ }
+ methodVisitor.visitAnnotableParameterCount(2, false);
+ {
+ annotationVisitor0 =
+ methodVisitor.visitParameterAnnotation(0, "Lorg/jetbrains/annotations/NotNull;", false);
+ annotationVisitor0.visitEnd();
+ }
+ methodVisitor.visitCode();
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitLdcInsn("param");
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "kotlin/jvm/internal/Intrinsics",
+ "checkParameterIsNotNull",
+ "(Ljava/lang/Object;Ljava/lang/String;)V",
+ false);
+ methodVisitor.visitVarInsn(ALOAD, 0);
+ methodVisitor.visitVarInsn(ILOAD, 1);
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;", false);
+ methodVisitor.visitMethodInsn(
+ INVOKEINTERFACE,
+ "kotlin/jvm/functions/Function1",
+ "invoke",
+ "(Ljava/lang/Object;)Ljava/lang/Object;",
+ true);
+ methodVisitor.visitInsn(POP);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(2, 2);
+ methodVisitor.visitEnd();
+ }
+ classWriter.visitEnd();
+
+ return classWriter.toByteArray();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/Test.kt b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/Test.kt
new file mode 100644
index 0000000..b213076
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/Test.kt
@@ -0,0 +1,9 @@
+// Copyright (c) 2020, 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.kotlin.lambda.b159688129
+
+fun test() {
+ run({ })
+}
diff --git a/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/TestKtDump.java b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/TestKtDump.java
new file mode 100644
index 0000000..cf66c3e
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/kotlin/lambda/b159688129/TestKtDump.java
@@ -0,0 +1,82 @@
+// Copyright (c) 2020, 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.kotlin.lambda.b159688129;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+
+public class TestKtDump implements Opcodes {
+
+ public static byte[] dump(int id) {
+
+ ClassWriter classWriter = new ClassWriter(0);
+ MethodVisitor methodVisitor;
+ AnnotationVisitor annotationVisitor0;
+
+ classWriter.visit(
+ V1_8,
+ ACC_PUBLIC | ACC_FINAL | ACC_SUPER,
+ "com/android/tools/r8/kotlin/lambda/b159688129/TestKt" + id,
+ null,
+ "java/lang/Object",
+ null);
+
+ {
+ annotationVisitor0 = classWriter.visitAnnotation("Lkotlin/Metadata;", true);
+ annotationVisitor0.visit("mv", new int[] {1, 1, 16});
+ annotationVisitor0.visit("bv", new int[] {1, 0, 3});
+ annotationVisitor0.visit("k", new Integer(2));
+ {
+ AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("d1");
+ annotationVisitor1.visit(
+ null,
+ "\u0000\u0008\n"
+ + "\u0000\n"
+ + "\u0002\u0010\u0002\n"
+ + "\u0000\u001a\u0006\u0010\u0000\u001a\u00020\u0001\u00a8\u0006\u0002");
+ annotationVisitor1.visitEnd();
+ }
+ {
+ AnnotationVisitor annotationVisitor1 = annotationVisitor0.visitArray("d2");
+ annotationVisitor1.visit(null, "test");
+ annotationVisitor1.visit(null, "");
+ annotationVisitor1.visit(null, "r8.main");
+ annotationVisitor1.visitEnd();
+ }
+ annotationVisitor0.visitEnd();
+ }
+ classWriter.visitInnerClass(
+ "com/android/tools/r8/kotlin/lambda/b159688129/TestKt" + id + "$test$1",
+ null,
+ null,
+ ACC_FINAL | ACC_STATIC);
+
+ {
+ methodVisitor =
+ classWriter.visitMethod(ACC_PUBLIC | ACC_FINAL | ACC_STATIC, "test", "()V", null, null);
+ methodVisitor.visitCode();
+ methodVisitor.visitFieldInsn(
+ GETSTATIC,
+ "com/android/tools/r8/kotlin/lambda/b159688129/TestKt" + id + "$test$1",
+ "INSTANCE",
+ "Lcom/android/tools/r8/kotlin/lambda/b159688129/TestKt" + id + "$test$1;");
+ methodVisitor.visitTypeInsn(CHECKCAST, "kotlin/jvm/functions/Function0");
+ methodVisitor.visitMethodInsn(
+ INVOKESTATIC,
+ "com/android/tools/r8/kotlin/lambda/b159688129/MainKt" + id,
+ "run",
+ "(Lkotlin/jvm/functions/Function0;)V",
+ false);
+ methodVisitor.visitInsn(RETURN);
+ methodVisitor.visitMaxs(1, 0);
+ methodVisitor.visitEnd();
+ }
+ classWriter.visitEnd();
+
+ return classWriter.toByteArray();
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/IllegalFieldRebindingTest.java b/src/test/java/com/android/tools/r8/memberrebinding/IllegalFieldRebindingTest.java
index ba40c07..4095713 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/IllegalFieldRebindingTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/IllegalFieldRebindingTest.java
@@ -49,7 +49,7 @@
.addInnerClasses(IllegalFieldRebindingTest.class)
.addInnerClasses(IllegalFieldRebindingTestClasses.class)
.addKeepMainRule(TestClass.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.run(TestClass.class)
.assertSuccessWithOutput(expectedOutput)
.inspector();
@@ -81,7 +81,7 @@
.addInnerClasses(IllegalFieldRebindingTest.class)
.addInnerClasses(IllegalFieldRebindingTestClasses.class)
.addKeepMainRule(OtherTestClass.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.run(OtherTestClass.class)
.assertSuccessWithOutput(expectedOutput)
.inspector();
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingBridgeRemovalTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingBridgeRemovalTest.java
index 77a9ea9..aa38f06 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingBridgeRemovalTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingBridgeRemovalTest.java
@@ -43,7 +43,7 @@
MemberRebindingBridgeRemovalTest.class, MemberRebindingBridgeRemovalTestClasses.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
.inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingConflictTest.java b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingConflictTest.java
index b1ae543..9d18387 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingConflictTest.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/MemberRebindingConflictTest.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.memberrebinding;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -48,7 +48,7 @@
.addInnerClasses(MemberRebindingConflictTestClasses.class)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -65,7 +65,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@NeverInline
@@ -74,7 +74,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public static class B extends A {
// public synthetic void foo() { super.foo(); }
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/testclasses/IllegalFieldRebindingTestClasses.java b/src/test/java/com/android/tools/r8/memberrebinding/testclasses/IllegalFieldRebindingTestClasses.java
index 64b4d1f..aaba050 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/testclasses/IllegalFieldRebindingTestClasses.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/testclasses/IllegalFieldRebindingTestClasses.java
@@ -4,11 +4,11 @@
package com.android.tools.r8.memberrebinding.testclasses;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
public class IllegalFieldRebindingTestClasses {
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
public static int f;
}
diff --git a/src/test/java/com/android/tools/r8/memberrebinding/testclasses/MemberRebindingBridgeRemovalTestClasses.java b/src/test/java/com/android/tools/r8/memberrebinding/testclasses/MemberRebindingBridgeRemovalTestClasses.java
index 3e15e6e..12ebac3 100644
--- a/src/test/java/com/android/tools/r8/memberrebinding/testclasses/MemberRebindingBridgeRemovalTestClasses.java
+++ b/src/test/java/com/android/tools/r8/memberrebinding/testclasses/MemberRebindingBridgeRemovalTestClasses.java
@@ -5,11 +5,11 @@
package com.android.tools.r8.memberrebinding.testclasses;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
public class MemberRebindingBridgeRemovalTestClasses {
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java b/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java
index 180541a..7d0d809 100644
--- a/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java
+++ b/src/test/java/com/android/tools/r8/naming/FieldMinificationCollisionTest.java
@@ -10,8 +10,8 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -33,7 +33,7 @@
.enableMemberValuePropagationAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.run(TestClass.class)
.assertSuccessWithOutput(expectedOutput)
.inspector();
@@ -54,7 +54,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@NeverPropagateValue public String f1;
@@ -64,7 +64,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class B extends A {
@NeverPropagateValue public String f2;
diff --git a/src/test/java/com/android/tools/r8/naming/InterfaceFieldMinificationTest.java b/src/test/java/com/android/tools/r8/naming/InterfaceFieldMinificationTest.java
index 4d43352..ca294fa 100644
--- a/src/test/java/com/android/tools/r8/naming/InterfaceFieldMinificationTest.java
+++ b/src/test/java/com/android/tools/r8/naming/InterfaceFieldMinificationTest.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.naming.testclasses.Greeting;
import com.android.tools.r8.utils.StringUtils;
@@ -25,7 +25,7 @@
.addKeepRules("-keep,allowobfuscation class " + Tag.class.getTypeName() + " { <fields>; }")
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.run(TestClass.class)
.assertSuccessWithOutput(expectedOutput);
}
@@ -50,7 +50,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface Tag {
String TAG = "Greeter";
diff --git a/src/test/java/com/android/tools/r8/naming/IntersectionLambdaTest.java b/src/test/java/com/android/tools/r8/naming/IntersectionLambdaTest.java
index 9a55cee..efb5d35 100644
--- a/src/test/java/com/android/tools/r8/naming/IntersectionLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/naming/IntersectionLambdaTest.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.naming;
import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -44,7 +44,7 @@
public void testR8() throws IOException, CompilationFailedException, ExecutionException {
testForR8(parameters.getBackend())
.addInnerClasses(IntersectionLambdaTest.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
@@ -52,7 +52,7 @@
}
@FunctionalInterface
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
}
diff --git a/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java b/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
index 5b26d4f..93a0639 100644
--- a/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
+++ b/src/test/java/com/android/tools/r8/naming/KotlinIntrinsicsIdentifierTest.java
@@ -15,6 +15,9 @@
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.kotlin.TestKotlinClass;
+import com.android.tools.r8.shaking.NoHorizontalClassMergingRule;
+import com.android.tools.r8.shaking.NoStaticClassMergingRule;
+import com.android.tools.r8.shaking.NoVerticalClassMergingRule;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -130,7 +133,9 @@
.addKeepRules(
StringUtils.lines(
"-neverclassinline class **." + targetClassName,
- "-nevermerge class **." + targetClassName,
+ "-" + NoVerticalClassMergingRule.RULE_NAME + " class **." + targetClassName,
+ "-" + NoHorizontalClassMergingRule.RULE_NAME + " class **." + targetClassName,
+ "-" + NoStaticClassMergingRule.RULE_NAME + " class **." + targetClassName,
"-neverinline class **." + targetClassName + " { <methods>; }"))
.allowDiagnosticWarningMessages()
.minification(minification)
diff --git a/src/test/java/com/android/tools/r8/naming/ReservedFieldNameInInterfacesWithCommonSubClassTest.java b/src/test/java/com/android/tools/r8/naming/ReservedFieldNameInInterfacesWithCommonSubClassTest.java
index e93b0fa..c4b3181 100644
--- a/src/test/java/com/android/tools/r8/naming/ReservedFieldNameInInterfacesWithCommonSubClassTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ReservedFieldNameInInterfacesWithCommonSubClassTest.java
@@ -10,7 +10,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.StringUtils;
@@ -45,7 +45,7 @@
CodeInspector inspector =
testForR8(Backend.DEX)
.addProgramClasses(TestClass.class, A.class, B.class, I.class, J.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addKeepMainRule(TestClass.class)
.addKeepRules(
reserveName
@@ -85,22 +85,22 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
String f1 = System.currentTimeMillis() >= 0 ? "Hello " : null;
}
- @NeverMerge
+ @NoVerticalClassMerging
interface J {
String a = System.currentTimeMillis() >= 0 ? "world!" : null;
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A implements I {}
- @NeverMerge
+ @NoVerticalClassMerging
static class B extends A implements J {
@Override
diff --git a/src/test/java/com/android/tools/r8/naming/ReservedFieldNameInSubClassTest.java b/src/test/java/com/android/tools/r8/naming/ReservedFieldNameInSubClassTest.java
index 67b86ce..38bcbad 100644
--- a/src/test/java/com/android/tools/r8/naming/ReservedFieldNameInSubClassTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ReservedFieldNameInSubClassTest.java
@@ -9,8 +9,8 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.utils.BooleanUtils;
@@ -52,7 +52,7 @@
.addProgramClasses(
TestClass.class, A.class, B.class, C.class, I.class, J.class, K.class)
.enableMemberValuePropagationAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addKeepMainRule(TestClass.class)
.addKeepRules(
reserveName
@@ -140,31 +140,31 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@NeverPropagateValue String f1 = "He";
}
- @NeverMerge
+ @NoVerticalClassMerging
static class B extends A {
@NeverPropagateValue String f2 = "l";
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
String f3 = System.currentTimeMillis() >= 0 ? "lo" : null;
}
- @NeverMerge
+ @NoVerticalClassMerging
interface J extends I {
String f4 = System.currentTimeMillis() >= 0 ? " " : null;
}
- @NeverMerge
+ @NoVerticalClassMerging
interface K {
String f5 = System.currentTimeMillis() >= 0 ? "world" : null;
diff --git a/src/test/java/com/android/tools/r8/naming/ReservedFieldNameInSubInterfaceTest.java b/src/test/java/com/android/tools/r8/naming/ReservedFieldNameInSubInterfaceTest.java
index 89804e8..65c62b8 100644
--- a/src/test/java/com/android/tools/r8/naming/ReservedFieldNameInSubInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/naming/ReservedFieldNameInSubInterfaceTest.java
@@ -10,8 +10,8 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assume.assumeFalse;
-import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.utils.BooleanUtils;
@@ -48,7 +48,7 @@
testForR8(Backend.DEX)
.addProgramClasses(TestClass.class, A.class, B.class, I.class, J.class)
.enableMemberValuePropagationAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addKeepMainRule(TestClass.class)
.addKeepRules(
reserveName
@@ -105,7 +105,7 @@
.addLibraryClasses(I.class, J.class)
.addLibraryFiles(runtimeJar(Backend.DEX))
.enableMemberValuePropagationAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addKeepMainRule(TestClass.class)
.compile()
.addRunClasspathFiles(
@@ -126,19 +126,19 @@
assertEquals(expectedNameForF2, f2FieldSubject.getFinalName());
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
String f1 = System.currentTimeMillis() >= 0 ? "Hello" : null;
}
- @NeverMerge
+ @NoVerticalClassMerging
interface J extends I {
String a = System.currentTimeMillis() >= 0 ? "world!" : null;
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@NeverPropagateValue String f2 = " ";
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java
index 7fa0543..4d000bb 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/ApplyMappingAfterVerticalMergingMethodTest.java
@@ -10,8 +10,8 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.R8TestCompileResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -81,7 +81,7 @@
}
private static final Class<?>[] LIBRARY_CLASSES = {
- NeverMerge.class, LibraryBase.class, LibrarySubclass.class
+ NoVerticalClassMerging.class, LibraryBase.class, LibrarySubclass.class
};
private static final Class<?>[] PROGRAM_CLASSES = {
diff --git a/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionTest.java b/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionTest.java
index 725c5a9..cbd6e3b 100644
--- a/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionTest.java
+++ b/src/test/java/com/android/tools/r8/naming/applymapping/sourcelibrary/MemberResolutionTest.java
@@ -8,8 +8,8 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -27,7 +27,7 @@
import org.junit.runners.Parameterized;
// AbstractChecker -> X:
-@NeverMerge
+@NoVerticalClassMerging
abstract class AbstractChecker {
// String tag -> p
@NeverPropagateValue private String tag = "PrivateInitialTag_AbstractChecker";
@@ -123,7 +123,7 @@
.addKeepMainRule(MemberResolutionTestMain.class)
.addKeepRules("-applymapping " + mapPath)
.enableMemberValuePropagationAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addOptionsModification(options -> options.enableInlining = false)
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), MemberResolutionTestMain.class)
diff --git a/src/test/java/com/android/tools/r8/naming/b116840216/ReserveOuterClassNameTest.java b/src/test/java/com/android/tools/r8/naming/b116840216/ReserveOuterClassNameTest.java
index 5da3af5..66b2a18 100644
--- a/src/test/java/com/android/tools/r8/naming/b116840216/ReserveOuterClassNameTest.java
+++ b/src/test/java/com/android/tools/r8/naming/b116840216/ReserveOuterClassNameTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.CompatProguardCommandBuilder;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
import com.android.tools.r8.R8Command;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.ToolHelper;
@@ -24,10 +24,10 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-@NeverMerge
+@NoStaticClassMerging
class Outer {
- @NeverMerge
+ @NoStaticClassMerging
static class Inner {
@NeverInline
static void foo() {
@@ -80,7 +80,7 @@
// the visiting of classes during class minification to be Outer$Inner before Outer.
"-keepnames class " + Outer.class.getCanonicalName() + "$Inner",
keepOuterName ? "-keepnames class " + Outer.class.getCanonicalName() : "",
- "-nevermerge @com.android.tools.r8.NeverMerge class *"),
+ noStaticClassMergingRule()),
Origin.unknown());
ToolHelper.allowTestProguardOptions(builder);
diff --git a/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java b/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java
index 56ed80c..0add817 100644
--- a/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java
+++ b/src/test/java/com/android/tools/r8/naming/b128656974/B128656974.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.naming.testclasses.Greeting;
import com.android.tools.r8.utils.StringUtils;
@@ -27,7 +27,7 @@
testForR8(Backend.DEX)
.addProgramClasses(Greeting.class, Greeting.getGreetingBase(), TestClassSub.class, main)
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addKeepMainRule(main)
.addKeepRules(
"-keepclassmembernames class "
@@ -74,7 +74,7 @@
Class<?> main = TestClassMainForMethod.class;
testForR8(Backend.DEX)
.addProgramClasses(TestClassBase.class, TestClassSub2.class, main)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addKeepMainRule(main)
@@ -92,7 +92,7 @@
});
}
- @NeverMerge
+ @NoVerticalClassMerging
static class TestClassBase {
@NeverInline
void foo() {
diff --git a/src/test/java/com/android/tools/r8/naming/testclasses/Greeting.java b/src/test/java/com/android/tools/r8/naming/testclasses/Greeting.java
index 221301b..20f6df1 100644
--- a/src/test/java/com/android/tools/r8/naming/testclasses/Greeting.java
+++ b/src/test/java/com/android/tools/r8/naming/testclasses/Greeting.java
@@ -4,9 +4,9 @@
package com.android.tools.r8.naming.testclasses;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
-@NeverMerge
+@NoVerticalClassMerging
public class Greeting extends GreetingBase {
public static Class<?> getGreetingBase() {
@@ -14,7 +14,7 @@
}
}
-@NeverMerge
+@NoVerticalClassMerging
class GreetingBase {
protected String greeting;
diff --git a/src/test/java/com/android/tools/r8/repackage/CrossPackageInvokeSuperToPackagePrivateMethodTest.java b/src/test/java/com/android/tools/r8/repackage/CrossPackageInvokeSuperToPackagePrivateMethodTest.java
index 32a8cc8..4e4001a 100644
--- a/src/test/java/com/android/tools/r8/repackage/CrossPackageInvokeSuperToPackagePrivateMethodTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/CrossPackageInvokeSuperToPackagePrivateMethodTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.R8TestRunResult;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestBuilder;
@@ -53,7 +53,7 @@
.apply(this::addProgramClasses)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -112,7 +112,7 @@
}
@NeverClassInline
- @NeverMerge
+ @NoVerticalClassMerging
public static class A {
@NeverInline
@@ -122,7 +122,7 @@
}
@NeverClassInline
- @NeverMerge
+ @NoVerticalClassMerging
public static class B extends A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java
index 1639c79..8e08452 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java
@@ -4,10 +4,11 @@
package com.android.tools.r8.repackage;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestBase;
@@ -25,8 +26,6 @@
@RunWith(Parameterized.class)
public class RepackageAfterCollisionWithPackagePrivateSignatureTest extends TestBase {
- private static final String FLATTEN_PACKAGE_HIERARCHY = "flattenpackagehierarchy";
- private static final String REPACKAGE_CLASSES = "repackageclasses";
private static final String REPACKAGE_DIR = "foo";
private final String flattenPackageHierarchyOrRepackageClasses;
@@ -76,7 +75,7 @@
public static void main(String[] args) {
RepackageCandidate.foo(0);
- RepackageCandidate.foo((int) System.currentTimeMillis(), 0);
+ RepackageCandidate.foo(System.currentTimeMillis(), 0);
}
static void restrictToCurrentPackage() {
@@ -86,12 +85,12 @@
public static class RepackageCandidate {
- public static void foo(int unused) {
+ public static void foo(long unused) {
TestClass.restrictToCurrentPackage();
}
@NeverInline
- public static void foo(int used, int unused) {
+ public static void foo(long used, int unused) {
if (used >= 0) {
System.out.println(" world!");
}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
index c656981..1d9718b 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
@@ -129,7 +129,7 @@
options ->
options.testing.enableExperimentalRepackaging = enableExperimentalRepackaging)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoStaticClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::inspect)
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithFeatureSplitTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithFeatureSplitTest.java
new file mode 100644
index 0000000..40e7721
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithFeatureSplitTest.java
@@ -0,0 +1,111 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.dexsplitter.SplitterTestBase.RunInterface;
+import com.android.tools.r8.dexsplitter.SplitterTestBase.SplitRunner;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackageWithFeatureSplitTest extends TestBase {
+
+ private static final String REPACKAGE_DIR = "foo";
+
+ private final String flattenPackageHierarchyOrRepackageClasses;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{1}, kind: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+ getTestParameters().withDexRuntimes().withAllApiLevels().build());
+ }
+
+ public RepackageWithFeatureSplitTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addProgramClasses(BaseClass.class)
+ .addFeatureSplit(FeatureMain.class, FeatureClass.class)
+ .addFeatureSplitRuntime()
+ .addKeepFeatureMainRule(FeatureMain.class)
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_DIR + "\"")
+ .addOptionsModification(
+ options -> {
+ assertFalse(options.testing.enableExperimentalRepackaging);
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ .enableInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspectBase, this::inspectFeature)
+ .runFeature(parameters.getRuntime(), FeatureMain.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void inspectBase(CodeInspector inspector) {
+ assertEquals(3, inspector.allClasses().size());
+
+ // The base classes added here.
+ assertThat(inspector.clazz(BaseClass.class), isPresent());
+
+ // The feature split runtime.
+ assertThat(inspector.clazz(RunInterface.class), isPresent());
+ assertThat(inspector.clazz(SplitRunner.class), isPresent());
+ }
+
+ private void inspectFeature(CodeInspector inspector) {
+ assertEquals(2, inspector.allClasses().size());
+ assertThat(inspector.clazz(FeatureMain.class), isPresent());
+ assertThat(inspector.clazz(FeatureClass.class), isPresent());
+ }
+
+ public static class BaseClass {
+
+ @NeverInline
+ public static void hello() {
+ System.out.print("Hello");
+ }
+ }
+
+ public static class FeatureMain implements RunInterface {
+
+ @Override
+ public void run() {
+ BaseClass.hello();
+ FeatureClass.world();
+ }
+ }
+
+ public static class FeatureClass {
+
+ @NeverInline
+ public static void world() {
+ System.out.println(" world!");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithInitClassTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithInitClassTest.java
new file mode 100644
index 0000000..501340a
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithInitClassTest.java
@@ -0,0 +1,98 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.Assert.assertEquals;
+
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackageWithInitClassTest extends TestBase {
+
+ private static final String REPACKAGE_PACKAGE = "foo";
+
+ private final String flattenPackageHierarchyOrRepackageClasses;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{1}, kind: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ public RepackageWithInitClassTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addClassObfuscationDictionary("a")
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_PACKAGE + "\"")
+ .addOptionsModification(
+ options -> {
+ assert !options.testing.enableExperimentalRepackaging;
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject repackagedClassSubject = inspector.clazz(StaticMemberValuePropagation.class);
+ assertThat(repackagedClassSubject, isPresent());
+
+ // Verify that a $r8$clinit field was synthesized.
+ String clinitFieldName = inspector.getFactory().objectMembers.clinitField.name.toSourceString();
+ assertThat(repackagedClassSubject.uniqueFieldWithName(clinitFieldName), isPresent());
+ assertThat(repackagedClassSubject.uniqueFieldWithName("GREETING"), not(isPresent()));
+
+ // Verify that the class was repackaged.
+ assertEquals(
+ flattenPackageHierarchyOrRepackageClasses.equals(FLATTEN_PACKAGE_HIERARCHY)
+ ? REPACKAGE_PACKAGE + ".a"
+ : REPACKAGE_PACKAGE,
+ repackagedClassSubject.getDexProgramClass().getType().getPackageName());
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ System.out.println(StaticMemberValuePropagation.GREETING);
+ }
+ }
+
+ public static class StaticMemberValuePropagation {
+
+ public static String GREETING = " world!";
+
+ static {
+ System.out.print("Hello");
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackagingWithNonReboundFieldReferenceTest.java b/src/test/java/com/android/tools/r8/repackage/RepackagingWithNonReboundFieldReferenceTest.java
new file mode 100644
index 0000000..c8a9d82
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackagingWithNonReboundFieldReferenceTest.java
@@ -0,0 +1,77 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.repackage.RepackageWithMainDexListTest.TestClass;
+import com.android.tools.r8.repackage.testclasses.RepackagingWithNonReboundFieldReferenceTestClasses;
+import com.android.tools.r8.repackage.testclasses.RepackagingWithNonReboundFieldReferenceTestClasses.B;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackagingWithNonReboundFieldReferenceTest extends TestBase {
+
+ private static final String REPACKAGE_DIR = "foo";
+
+ private final String flattenPackageHierarchyOrRepackageClasses;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{1}, kind: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ public RepackagingWithNonReboundFieldReferenceTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ try {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass(), RepackagingWithNonReboundFieldReferenceTestClasses.class)
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_DIR + "\"")
+ .addOptionsModification(
+ options -> {
+ assertFalse(options.testing.enableExperimentalRepackaging);
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ .enableMemberValuePropagationAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile();
+
+ // TODO(b/168282032): Support lens rewriting of non-rebound references in the writer.
+ fail();
+ } catch (CompilationFailedException exception) {
+ // Ignore.
+ }
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ System.out.println(B.GREETING);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackagingWithNonReboundMethodReferenceTest.java b/src/test/java/com/android/tools/r8/repackage/RepackagingWithNonReboundMethodReferenceTest.java
new file mode 100644
index 0000000..48891e7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackagingWithNonReboundMethodReferenceTest.java
@@ -0,0 +1,77 @@
+// Copyright (c) 2020, 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.repackage;
+
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.FLATTEN_PACKAGE_HIERARCHY;
+import static com.android.tools.r8.shaking.ProguardConfigurationParser.REPACKAGE_CLASSES;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.fail;
+
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.repackage.testclasses.RepackagingWithNonReboundMethodReferenceTestClasses;
+import com.android.tools.r8.repackage.testclasses.RepackagingWithNonReboundMethodReferenceTestClasses.B;
+import com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
+
+@RunWith(Parameterized.class)
+public class RepackagingWithNonReboundMethodReferenceTest extends TestBase {
+
+ private static final String REPACKAGE_DIR = "foo";
+
+ private final String flattenPackageHierarchyOrRepackageClasses;
+ private final TestParameters parameters;
+
+ @Parameters(name = "{1}, kind: {0}")
+ public static List<Object[]> data() {
+ return buildParameters(
+ ImmutableList.of(FLATTEN_PACKAGE_HIERARCHY, REPACKAGE_CLASSES),
+ getTestParameters().withAllRuntimesAndApiLevels().build());
+ }
+
+ public RepackagingWithNonReboundMethodReferenceTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ try {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass(), RepackagingWithNonReboundMethodReferenceTestClasses.class)
+ .addKeepMainRule(TestClass.class)
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_DIR + "\"")
+ .addOptionsModification(
+ options -> {
+ assertFalse(options.testing.enableExperimentalRepackaging);
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile();
+
+ // TODO(b/168282032): Support lens rewriting of non-rebound references in the writer.
+ fail();
+ } catch (CompilationFailedException exception) {
+ // Ignore.
+ }
+ }
+
+ static class TestClass {
+
+ public static void main(String[] args) {
+ new B().greet();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/CrossPackageInvokeSuperToPackagePrivateMethodTestClasses.java b/src/test/java/com/android/tools/r8/repackage/testclasses/CrossPackageInvokeSuperToPackagePrivateMethodTestClasses.java
index fc9639a..c9c8690 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/CrossPackageInvokeSuperToPackagePrivateMethodTestClasses.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/CrossPackageInvokeSuperToPackagePrivateMethodTestClasses.java
@@ -6,13 +6,13 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.repackage.CrossPackageInvokeSuperToPackagePrivateMethodTest;
public class CrossPackageInvokeSuperToPackagePrivateMethodTestClasses {
@NeverClassInline
- @NeverMerge
+ @NoVerticalClassMerging
public static class C extends CrossPackageInvokeSuperToPackagePrivateMethodTest.B {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/RepackagingWithNonReboundFieldReferenceTestClasses.java b/src/test/java/com/android/tools/r8/repackage/testclasses/RepackagingWithNonReboundFieldReferenceTestClasses.java
new file mode 100644
index 0000000..b33496f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/RepackagingWithNonReboundFieldReferenceTestClasses.java
@@ -0,0 +1,19 @@
+// Copyright (c) 2020, 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.repackage.testclasses;
+
+import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.NoVerticalClassMerging;
+
+public class RepackagingWithNonReboundFieldReferenceTestClasses {
+
+ @NoVerticalClassMerging
+ static class A {
+
+ @NeverPropagateValue public static String GREETING = "Hello world!";
+ }
+
+ public static class B extends A {}
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/RepackagingWithNonReboundMethodReferenceTestClasses.java b/src/test/java/com/android/tools/r8/repackage/testclasses/RepackagingWithNonReboundMethodReferenceTestClasses.java
new file mode 100644
index 0000000..fb4775f
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/RepackagingWithNonReboundMethodReferenceTestClasses.java
@@ -0,0 +1,24 @@
+// Copyright (c) 2020, 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.repackage.testclasses;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.NoVerticalClassMerging;
+
+public class RepackagingWithNonReboundMethodReferenceTestClasses {
+
+ @NeverClassInline
+ @NoVerticalClassMerging
+ static class A {
+
+ @NeverInline
+ public void greet() {
+ System.out.println("Hello world!");
+ }
+ }
+
+ public static class B extends A {}
+}
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassDirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassDirect.java
index 8089eb2..4f47751 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassDirect.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassDirect.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassDirect {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassIndirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassIndirect.java
index c7c3695..fdc4a9c 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassIndirect.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassIndirect.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPackagePrivateKeptMethodAllowRenamingOnReachableClassIndirect {
@NeverInline
@@ -15,7 +15,7 @@
Helper.test();
}
- @NeverMerge
+ @NoStaticClassMerging
public static class Helper {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassDirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassDirect.java
index 6948b55..0f9ae96 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassDirect.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassDirect.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPackagePrivateKeptMethodOnReachableClassDirect {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassIndirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassIndirect.java
index 7d5baae..68aa391 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassIndirect.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateKeptMethodOnReachableClassIndirect.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPackagePrivateKeptMethodOnReachableClassIndirect {
@NeverInline
@@ -15,7 +15,7 @@
Helper.test();
}
- @NeverMerge
+ @NoStaticClassMerging
public static class Helper {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingDirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingDirect.java
index f3a90e6..de0e859 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingDirect.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingDirect.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPackagePrivateMethodOnKeptClassAllowRenamingDirect {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingIndirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingIndirect.java
index ddfd95b..13fef6e 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingIndirect.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassAllowRenamingIndirect.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPackagePrivateMethodOnKeptClassAllowRenamingIndirect {
@NeverInline
@@ -15,7 +15,7 @@
Helper.test();
}
- @NeverMerge
+ @NoStaticClassMerging
public static class Helper {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassDirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassDirect.java
index 11110bd..fc92f85 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassDirect.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassDirect.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPackagePrivateMethodOnKeptClassDirect {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassIndirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassIndirect.java
index 0b737ff..c30cd59 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassIndirect.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnKeptClassIndirect.java
@@ -5,9 +5,10 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
+import com.android.tools.r8.NoVerticalClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPackagePrivateMethodOnKeptClassIndirect {
@NeverInline
@@ -15,7 +16,7 @@
Helper.test();
}
- @NeverMerge
+ @NoVerticalClassMerging
public static class Helper {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassDirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassDirect.java
index f9a5b76..73f2d6e 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassDirect.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassDirect.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPackagePrivateMethodOnReachableClassDirect {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassIndirect.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassIndirect.java
index 2c0a1b2..54cbea9 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassIndirect.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPackagePrivateMethodOnReachableClassIndirect.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPackagePrivateMethodOnReachableClassIndirect {
@NeverInline
@@ -15,7 +15,7 @@
Helper.test();
}
- @NeverMerge
+ @NoStaticClassMerging
public static class Helper {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodAllowRenamingOnReachableClass.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodAllowRenamingOnReachableClass.java
index 0f54397..cfb5aa4 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodAllowRenamingOnReachableClass.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodAllowRenamingOnReachableClass.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPublicKeptMethodAllowRenamingOnReachableClass {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodOnReachableClass.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodOnReachableClass.java
index dcd6aa4..75d353c 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodOnReachableClass.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicKeptMethodOnReachableClass.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPublicKeptMethodOnReachableClass {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClass.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClass.java
index f6cf98a..b77f419 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClass.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClass.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPublicMethodOnKeptClass {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClassAllowRenaming.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClassAllowRenaming.java
index 05f943c..f71b585 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClassAllowRenaming.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnKeptClassAllowRenaming.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPublicMethodOnKeptClassAllowRenaming {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnReachableClass.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnReachableClass.java
index 0c21cef..87ed71f 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnReachableClass.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/AccessPublicMethodOnReachableClass.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class AccessPublicMethodOnReachableClass {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/ReachableClass.java b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/ReachableClass.java
index 57b2d65..10f12bf 100644
--- a/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/ReachableClass.java
+++ b/src/test/java/com/android/tools/r8/repackage/testclasses/repackagetest/ReachableClass.java
@@ -5,9 +5,9 @@
package com.android.tools.r8.repackage.testclasses.repackagetest;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class ReachableClass {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java
index 440e077..3215f17 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodAsOverrideWithLambdaTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -85,7 +85,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(DefaultMethodAsOverrideWithLambdaTest.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
@@ -94,7 +94,7 @@
}
@FunctionalInterface
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
@@ -103,7 +103,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface J extends I {
@Override
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java
index edbb580..77fa9d8 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultMethodLambdaTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -81,7 +81,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(DefaultMethodLambdaTest.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
@@ -90,7 +90,7 @@
}
@FunctionalInterface
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
index 8d2a599..70a350f 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DefaultWithoutTopTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -144,12 +144,12 @@
return transformer(A.class).setImplements(I.class, K.class).transform();
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface J {
@NeverInline
default void foo() {
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
index ef5656d..8b1f615 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/DuplicateImportsTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -82,7 +82,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(DuplicateImportsTest.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
@@ -90,12 +90,12 @@
.assertSuccessWithOutputLines(EXPECTED);
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface J extends I {
@Override
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java
index 0702c97..5422f9b 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/LambdaMultipleInterfacesTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -82,7 +82,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(LambdaMultipleInterfacesTest.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
@@ -91,7 +91,7 @@
}
@FunctionalInterface
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
index 5ad3690..eb88c69 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/MultipleImplementsTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -82,7 +82,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(MultipleImplementsTest.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
@@ -90,17 +90,17 @@
.assertSuccessWithOutputLines(EXPECTED);
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface J {
void foo();
}
- @NeverMerge
+ @NoVerticalClassMerging
public abstract static class A implements I, J {}
@NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java
index 4d195e1..ec16d6d 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SimpleInterfaceInvokeTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -89,7 +89,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(SimpleInterfaceInvokeTest.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
@@ -97,7 +97,7 @@
.assertSuccessWithOutputLines(EXPECTED);
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
}
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java
index 51727c7..3e582c5 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubInterfaceOverridesTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -88,7 +88,7 @@
public void testR8() throws IOException, CompilationFailedException, ExecutionException {
testForR8(parameters.getBackend())
.addInnerClasses(SubInterfaceOverridesTest.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
@@ -97,13 +97,13 @@
.assertSuccessWithOutputLines(EXPECTED);
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface J extends I {
@Override
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
index 9c02be6..5628ea2 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeMissingOverridesTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -87,7 +87,7 @@
public void testR8() throws IOException, CompilationFailedException, ExecutionException {
testForR8(parameters.getBackend())
.addInnerClasses(SubTypeMissingOverridesTest.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
@@ -96,7 +96,7 @@
.assertSuccessWithOutputLines(EXPECTED);
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
diff --git a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java
index d5d1ce8..65d8bca 100644
--- a/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/interfacetargets/SubTypeOverridesTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -87,7 +87,7 @@
public void testR8() throws IOException, CompilationFailedException, ExecutionException {
testForR8(parameters.getBackend())
.addInnerClasses(SubTypeOverridesTest.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
@@ -96,7 +96,7 @@
.assertSuccessWithOutputLines(EXPECTED);
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
index 7f52044..787f992 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/AbstractInMiddleTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -83,7 +83,7 @@
public void testR8() throws IOException, CompilationFailedException, ExecutionException {
testForR8(parameters.getBackend())
.addInnerClasses(AbstractInMiddleTest.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.addKeepMainRule(Main.class)
@@ -92,7 +92,7 @@
.assertSuccessWithOutputLines(EXPECTED);
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
public static class A {
@@ -102,14 +102,14 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public abstract static class B extends A {
@Override
public abstract void foo();
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
public static class C extends B {
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
index 6264f35..80b6908 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceSubTypeTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -83,18 +83,18 @@
.addKeepMainRule(Main.class)
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines(EXPECTED);
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface J extends I {
@Override
@NeverInline
@@ -103,7 +103,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public abstract static class A implements I {}
@NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
index 8f818b2..a4966b4 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultInterfaceMethodInSubInterfaceTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -83,18 +83,18 @@
.addKeepMainRule(Main.class)
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines(EXPECTED);
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface J extends I {
@Override
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
index 2b236b5..0daaa44 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/DefaultWithoutTopTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -95,12 +95,12 @@
return transformer(A.class).setImplements(I.class, J.class).transform();
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
void foo();
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface J {
@NeverInline
default void foo() {
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
index 9c7245c..dcb03f9 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/InvokeVirtualToInterfaceDefinitionTest.java
@@ -12,7 +12,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -82,13 +82,13 @@
.addKeepMainRule(Main.class)
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
.assertSuccessWithOutputLines(EXPECTED);
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java b/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
index fbf8ac5..c1f2301 100644
--- a/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
+++ b/src/test/java/com/android/tools/r8/resolution/virtualtargets/TargetInDefaultMethodTest.java
@@ -13,7 +13,7 @@
import com.android.tools.r8.CompilationFailedException;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -89,7 +89,7 @@
testForR8(parameters.getBackend())
.addInnerClasses(TargetInDefaultMethodTest.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addKeepMainRule(Main.class)
.setMinApi(parameters.getApiLevel())
@@ -97,7 +97,7 @@
.assertSuccessWithOutputLines(EXPECTED);
}
- @NeverMerge
+ @NoVerticalClassMerging
public interface I {
@NeverInline
default void foo() {
@@ -105,7 +105,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public abstract static class A implements I {}
@NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/shaking/B149831282.java b/src/test/java/com/android/tools/r8/shaking/B149831282.java
index 97441cc..67b9bca 100644
--- a/src/test/java/com/android/tools/r8/shaking/B149831282.java
+++ b/src/test/java/com/android/tools/r8/shaking/B149831282.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestBuilder;
import com.android.tools.r8.TestParameters;
@@ -46,7 +46,7 @@
.apply(this::addProgramInputs)
.addKeepMainRule(TestClass.class)
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
@@ -84,7 +84,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@NeverInline
@@ -93,7 +93,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public static class B extends A {}
@NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
index 66c8152..745e5b7 100644
--- a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalInstanceFieldsTest.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -53,7 +53,7 @@
.addKeepMainRule(MAIN)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
.inspect(
@@ -154,7 +154,7 @@
}
@NeverClassInline
- @NeverMerge
+ @NoVerticalClassMerging
static class InstanceFieldWithInitialization_Z {
boolean alwaysFalse;
InstanceFieldWithInitialization_Z() {
diff --git a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java
index 302cb28..35cd9c9 100644
--- a/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/EffectivelyFinalStaticFieldsTest.java
@@ -11,7 +11,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -53,7 +53,7 @@
.addKeepMainRule(MAIN)
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
.inspect(
@@ -147,7 +147,7 @@
}
@NeverClassInline
- @NeverMerge
+ @NoVerticalClassMerging
static class StaticFieldWithInitialization_Z {
static boolean alwaysFalse;
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/shaking/EventuallyNonTargetedMethodTest.java b/src/test/java/com/android/tools/r8/shaking/EventuallyNonTargetedMethodTest.java
index 741496d..382f515 100644
--- a/src/test/java/com/android/tools/r8/shaking/EventuallyNonTargetedMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/EventuallyNonTargetedMethodTest.java
@@ -8,7 +8,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -39,7 +39,7 @@
public void test() throws Exception {
testForR8(parameters.getBackend())
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addInnerClasses(EventuallyNonTargetedMethodTest.class)
.addKeepMainRule(Main.class)
@@ -56,7 +56,7 @@
assertThat(classSubject.uniqueMethodWithName("foo"), isPresent());
}
- @NeverMerge
+ @NoVerticalClassMerging
private static class A {
@NeverInline
public void foo() {
@@ -64,7 +64,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
private static class B extends A {
// No override of foo, but B::foo will be the only target.
diff --git a/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInInterfaceMarkingTest.java b/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInInterfaceMarkingTest.java
index bff8192..437cdd2 100644
--- a/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInInterfaceMarkingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInInterfaceMarkingTest.java
@@ -6,7 +6,7 @@
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -40,7 +40,7 @@
.addKeepMainRule(TestClass.class)
.addOptionsModification(
options -> options.testing.enqueuerInspector = this::verifyLibraryOverrideInformation)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutputLines("true", "true");
@@ -79,7 +79,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
abstract static class A extends AbstractList<Object> {
@Override
@@ -98,13 +98,13 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
boolean isEmpty();
}
- @NeverMerge
+ @NoVerticalClassMerging
static class B extends A implements I {
// Intentionally empty.
}
diff --git a/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInLambdaMarkingTest.java b/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInLambdaMarkingTest.java
index 9d16769..7d68070 100644
--- a/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInLambdaMarkingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideInLambdaMarkingTest.java
@@ -6,7 +6,7 @@
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -43,7 +43,7 @@
.addKeepMainRule(TestClass.class)
.addOptionsModification(
options -> options.testing.enqueuerInspector = this::verifyLibraryOverrideInformation)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutputLines("null", "null");
@@ -88,14 +88,14 @@
}
@FunctionalInterface
- @NeverMerge
+ @NoVerticalClassMerging
interface I {
Iterator<Object> iterator();
}
@FunctionalInterface
- @NeverMerge
+ @NoVerticalClassMerging
interface J extends Iterable<Object> {
@Override
diff --git a/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideMarkingTest.java b/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideMarkingTest.java
index df8fdc4..a7908c2 100644
--- a/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideMarkingTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/LibraryMethodOverrideMarkingTest.java
@@ -8,7 +8,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -41,7 +41,7 @@
.addKeepMainRule(TestClass.class)
.addOptionsModification(
options -> options.testing.enqueuerInspector = this::verifyLibraryOverrideInformation)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile();
}
@@ -69,7 +69,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
@Override
@@ -78,7 +78,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class B extends A {
@Override
diff --git a/src/test/java/com/android/tools/r8/shaking/NonTargetedMethodTest.java b/src/test/java/com/android/tools/r8/shaking/NonTargetedMethodTest.java
index 8f560a2..f813bf2 100644
--- a/src/test/java/com/android/tools/r8/shaking/NonTargetedMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/NonTargetedMethodTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -40,7 +40,7 @@
public void test() throws Exception {
testForR8(parameters.getBackend())
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addInnerClasses(NonTargetedMethodTest.class)
.addKeepMainRule(Main.class)
@@ -56,7 +56,7 @@
assertThat(classSubject.uniqueMethodWithName("foo"), not(isPresent()));
}
- @NeverMerge
+ @NoVerticalClassMerging
private static class A {
@NeverInline
public void foo() {
@@ -64,7 +64,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
@NeverClassInline
private static class B extends A {
// No override of foo, but B::foo will be the only target.
diff --git a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnTargetedMethodTest.java b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnTargetedMethodTest.java
index f4917c7..c4d9068 100644
--- a/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnTargetedMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/annotations/AnnotationsOnTargetedMethodTest.java
@@ -5,7 +5,7 @@
package com.android.tools.r8.shaking.annotations;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -54,7 +54,7 @@
.addKeepMainRule(TestClass.class)
.addKeepRules("-keepattributes *Annotation*", "-dontobfuscate")
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), TestClass.class)
.assertSuccessWithOutput(expectedOutput);
@@ -83,7 +83,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface Interface {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithoutMatchingDefinitionTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithoutMatchingDefinitionTest.java
index 9c38214..8462593 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithoutMatchingDefinitionTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsPropagationWithoutMatchingDefinitionTest.java
@@ -9,7 +9,7 @@
import static org.junit.Assert.assertTrue;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -43,7 +43,7 @@
public void testR8() throws Exception {
testForR8(parameters.getBackend())
.addInnerClasses(AssumenosideeffectsPropagationWithoutMatchingDefinitionTest.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableInliningAnnotations()
.addKeepMainRule(MAIN)
.addKeepRules(
@@ -76,7 +76,7 @@
void debug(String tag, String message);
}
- @NeverMerge
+ @NoVerticalClassMerging
static class BaseImplementer implements LoggerInterface {
@Override
public void debug(String message) {
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
index 71614d2..6b053ee 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsVisibleMethodsTest.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.DexIndexedConsumer.ArchiveConsumer;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.ToolHelper;
@@ -157,7 +157,7 @@
.addKeepMainRule(MAIN)
.addKeepRules(config.getKeepRule())
.noMinification()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.setMinApi(parameters.getApiLevel())
@@ -178,7 +178,7 @@
}
@NeverClassInline
- @NeverMerge
+ @NoVerticalClassMerging
static class ProgramBase extends LibraryBase {
@NeverInline
@Override
diff --git a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java
index 34b1b33..daaacb2 100644
--- a/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/assumenosideeffects/AssumenosideeffectsWithMultipleTargetsTest.java
@@ -10,7 +10,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.errors.Unreachable;
@@ -93,7 +93,7 @@
public void testR8() throws Exception {
testForR8(parameters.getBackend())
.addInnerClasses(AssumenosideeffectsWithMultipleTargetsTest.class)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
.addKeepMainRule(MAIN)
@@ -109,9 +109,8 @@
void info(String tag, String message);
}
- @NeverMerge
- static abstract class AbstractLogger implements TestLogger {
- }
+ @NoVerticalClassMerging
+ abstract static class AbstractLogger implements TestLogger {}
@NeverClassInline
static class TestLoggerImplementer implements TestLogger {
diff --git a/src/test/java/com/android/tools/r8/shaking/desugar/KeepRuleWarningTest.java b/src/test/java/com/android/tools/r8/shaking/desugar/KeepRuleWarningTest.java
index 27bb092..c2be7a8 100644
--- a/src/test/java/com/android/tools/r8/shaking/desugar/KeepRuleWarningTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/desugar/KeepRuleWarningTest.java
@@ -5,7 +5,7 @@
import static org.hamcrest.CoreMatchers.containsString;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestDiagnosticMessages;
import com.android.tools.r8.TestParameters;
@@ -17,7 +17,7 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
-@NeverMerge
+@NoVerticalClassMerging
interface I {
static void foo() {
System.out.println("static::foo");
@@ -61,7 +61,7 @@
testForR8(parameters.getBackend())
.addProgramClasses(I.class, C.class, MAIN)
.setMinApi(parameters.getApiLevel())
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addKeepMainRule(MAIN)
.addKeepRules("-keep interface **.I { <methods>; }")
.compile()
@@ -75,7 +75,7 @@
testForR8(parameters.getBackend())
.addProgramClasses(I.class, C.class, MAIN)
.setMinApi(parameters.getApiLevel())
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addKeepMainRule(MAIN)
.addKeepRules("-keep interface **.I { *(); }")
.compile()
@@ -89,7 +89,7 @@
testForR8(parameters.getBackend())
.addProgramClasses(I.class, C.class, MAIN)
.setMinApi(parameters.getApiLevel())
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addKeepMainRule(MAIN)
.addKeepRules("-keep interface **.I { *** f*(); }")
.compile()
@@ -103,7 +103,7 @@
testForR8(parameters.getBackend())
.addProgramClasses(I.class, C.class, MAIN)
.setMinApi(parameters.getApiLevel())
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addKeepMainRule(MAIN)
.addKeepRules("-keep interface **.I { static void foo(); }")
.allowDiagnosticWarningMessages()
diff --git a/src/test/java/com/android/tools/r8/shaking/desugar/dflt/DefaultMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/desugar/dflt/DefaultMethodsTest.java
index 8c782f2..14c99ba 100644
--- a/src/test/java/com/android/tools/r8/shaking/desugar/dflt/DefaultMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/desugar/dflt/DefaultMethodsTest.java
@@ -10,7 +10,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.shaking.methods.MethodsTestBase.Shrinker;
import com.android.tools.r8.utils.AndroidApiLevel;
@@ -26,32 +26,32 @@
import java.util.function.Function;
import org.junit.Test;
-@NeverMerge
+@NoVerticalClassMerging
interface SuperIface {
default void m1() {}
}
-@NeverMerge
+@NoVerticalClassMerging
interface SubIface extends SuperIface {
default void m2() {}
}
-@NeverMerge
+@NoVerticalClassMerging
interface SubSubIface extends SubIface {
default void m3() {}
}
-@NeverMerge
+@NoVerticalClassMerging
class Impl implements SubSubIface {
void m4() {}
}
-@NeverMerge
+@NoVerticalClassMerging
class SubImpl extends Impl {
void m5() {}
}
-@NeverMerge
+@NoVerticalClassMerging
class SubSubImpl extends SubImpl {
void m6() {}
}
@@ -111,7 +111,7 @@
throws Throwable {
testForR8(Backend.DEX)
.setMinApi(AndroidApiLevel.L)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addProgramClasses(getClasses())
.addKeepRules(keepRules)
.compile()
@@ -125,7 +125,7 @@
throws Throwable {
testForR8Compat(Backend.DEX)
.setMinApi(AndroidApiLevel.L)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addProgramClasses(getClasses())
.addKeepRules(keepRules)
.compile()
diff --git a/src/test/java/com/android/tools/r8/shaking/desugar/interfacemethods/BridgeInliningTest.java b/src/test/java/com/android/tools/r8/shaking/desugar/interfacemethods/BridgeInliningTest.java
index 5f6a618..a48c5e9 100644
--- a/src/test/java/com/android/tools/r8/shaking/desugar/interfacemethods/BridgeInliningTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/desugar/interfacemethods/BridgeInliningTest.java
@@ -7,7 +7,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.StringUtils;
@@ -17,7 +17,7 @@
import java.lang.reflect.Method;
import org.junit.Test;
-@NeverMerge
+@NoVerticalClassMerging
interface I {
default void m() {
System.out.println("I::m");
@@ -45,7 +45,7 @@
testForR8(Backend.DEX)
.addProgramClasses(I.class, C.class, MAIN)
.setMinApi(AndroidApiLevel.L)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addKeepMainRule(MAIN)
.addKeepRules("-keep interface **.I { m(); }")
.run(MAIN)
diff --git a/src/test/java/com/android/tools/r8/shaking/fields/FieldsTestBase.java b/src/test/java/com/android/tools/r8/shaking/fields/FieldsTestBase.java
index 061e91a..c461169 100644
--- a/src/test/java/com/android/tools/r8/shaking/fields/FieldsTestBase.java
+++ b/src/test/java/com/android/tools/r8/shaking/fields/FieldsTestBase.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.shaking.fields;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ThrowingConsumer;
@@ -25,7 +25,7 @@
String expected)
throws Throwable {
testForR8(Backend.DEX)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addProgramClasses(getClasses())
.addKeepRules(keepRules)
.compile()
@@ -41,7 +41,7 @@
throws Throwable {
testForProguard()
.addProgramClasses(getClasses())
- .addProgramClasses(NeverMerge.class)
+ .addProgramClasses(NoVerticalClassMerging.class)
.addKeepRules(keepRules)
.compile()
.inspect(inspector)
diff --git a/src/test/java/com/android/tools/r8/shaking/fields/pblc/PublicFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/fields/pblc/PublicFieldsTest.java
index 7ac89e0..f2f68d8 100644
--- a/src/test/java/com/android/tools/r8/shaking/fields/pblc/PublicFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/fields/pblc/PublicFieldsTest.java
@@ -8,7 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.shaking.fields.FieldsTestBase;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -17,17 +17,17 @@
import java.util.Set;
import org.junit.Test;
-@NeverMerge
+@NoVerticalClassMerging
class Super {
public int f1;
}
-@NeverMerge
+@NoVerticalClassMerging
class Sub extends Super {
public int f2;
}
-@NeverMerge
+@NoVerticalClassMerging
class SubSub extends Sub {
public int f3;
}
diff --git a/src/test/java/com/android/tools/r8/shaking/fields/pckg/PackageFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/fields/pckg/PackageFieldsTest.java
index 86c22f6..113b862 100644
--- a/src/test/java/com/android/tools/r8/shaking/fields/pckg/PackageFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/fields/pckg/PackageFieldsTest.java
@@ -8,7 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.shaking.fields.FieldsTestBase;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -17,17 +17,17 @@
import java.util.Set;
import org.junit.Test;
-@NeverMerge
+@NoVerticalClassMerging
class Super {
int f1;
}
-@NeverMerge
+@NoVerticalClassMerging
class Sub extends Super {
int f2;
}
-@NeverMerge
+@NoVerticalClassMerging
class SubSub extends Sub {
int f3;
}
diff --git a/src/test/java/com/android/tools/r8/shaking/fields/prvt/PrivateFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/fields/prvt/PrivateFieldsTest.java
index 0ceefb4..e70f0a3 100644
--- a/src/test/java/com/android/tools/r8/shaking/fields/prvt/PrivateFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/fields/prvt/PrivateFieldsTest.java
@@ -8,7 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.shaking.fields.FieldsTestBase;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -17,17 +17,17 @@
import java.util.Set;
import org.junit.Test;
-@NeverMerge
+@NoVerticalClassMerging
class Super {
private int f1;
}
-@NeverMerge
+@NoVerticalClassMerging
class Sub extends Super {
private int f2;
}
-@NeverMerge
+@NoVerticalClassMerging
class SubSub extends Sub {
private int f3;
}
diff --git a/src/test/java/com/android/tools/r8/shaking/fields/shadow/ShadowFieldsTest.java b/src/test/java/com/android/tools/r8/shaking/fields/shadow/ShadowFieldsTest.java
index 6cc26a6..da756b3 100644
--- a/src/test/java/com/android/tools/r8/shaking/fields/shadow/ShadowFieldsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/fields/shadow/ShadowFieldsTest.java
@@ -7,7 +7,7 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
import static org.hamcrest.MatcherAssert.assertThat;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.shaking.fields.FieldsTestBase;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -16,17 +16,17 @@
import java.util.Collection;
import org.junit.Test;
-@NeverMerge
+@NoVerticalClassMerging
class Super {
public int f1;
}
-@NeverMerge
+@NoVerticalClassMerging
class Sub extends Super {
public int f1;
}
-@NeverMerge
+@NoVerticalClassMerging
class SubSub extends Sub {
public int f1;
}
diff --git a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
index b79d90e..a969d1b 100644
--- a/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/ifrule/interfacemethoddesugaring/IfRuleWithInterfaceMethodDesugaringTest.java
@@ -9,14 +9,13 @@
import static com.android.tools.r8.utils.codeinspector.Matchers.isPublic;
import static com.android.tools.r8.utils.codeinspector.Matchers.isStatic;
import static org.hamcrest.CoreMatchers.allOf;
-import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -67,7 +66,7 @@
.allowUnusedProguardConfigurationRules()
.enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.run(parameters.getRuntime(), TestClass.class)
@@ -104,7 +103,7 @@
}
@NeverClassInline
- @NeverMerge
+ @NoVerticalClassMerging
interface Interface {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/shaking/keepclassmembers/KeepClassMembersRuleOnIndirectlyInstantiatedClassTest.java b/src/test/java/com/android/tools/r8/shaking/keepclassmembers/KeepClassMembersRuleOnIndirectlyInstantiatedClassTest.java
index 5b47f4f..9dd4b60 100644
--- a/src/test/java/com/android/tools/r8/shaking/keepclassmembers/KeepClassMembersRuleOnIndirectlyInstantiatedClassTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keepclassmembers/KeepClassMembersRuleOnIndirectlyInstantiatedClassTest.java
@@ -9,7 +9,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -45,7 +45,7 @@
" java.lang.String greeting;",
"}")
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getRuntime())
.compile()
.inspect(this::verifyFieldIsPresent)
@@ -82,7 +82,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class A {
public String greeting;
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByReachableSubclassTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByReachableSubclassTest.java
index 2ce88f3..528a4ac 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByReachableSubclassTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByReachableSubclassTest.java
@@ -7,7 +7,7 @@
import static org.junit.Assert.assertEquals;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersBuilder;
@@ -44,7 +44,7 @@
GraphInspector inspector =
testForR8(parameters.getBackend())
.enableGraphInspector()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableInliningAnnotations()
.addProgramClasses(CLASS, A.class, B.class)
.addKeepMainRule(CLASS)
@@ -72,7 +72,7 @@
}
// Base class, A.foo never resolved to at runtime.
- @NeverMerge
+ @NoVerticalClassMerging
public static class A {
@NeverInline
@@ -82,7 +82,7 @@
}
// Actual and only instantiated type.
- @NeverMerge
+ @NoVerticalClassMerging
public static class B extends A {
@NeverInline
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByTwoMethods.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByTwoMethods.java
index 8a67d39..5bb8e48 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByTwoMethods.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptByTwoMethods.java
@@ -6,7 +6,7 @@
import static com.android.tools.r8.references.Reference.methodFromMethod;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -22,7 +22,7 @@
@RunWith(Parameterized.class)
public class KeptByTwoMethods extends TestBase {
- @NeverMerge
+ @NoVerticalClassMerging
public static class A {
@NeverInline
@@ -31,7 +31,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
public static class B extends A {
// Intermediate to A.
}
@@ -72,7 +72,7 @@
GraphInspector inspector =
testForR8(parameters.getBackend())
.enableGraphInspector()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableInliningAnnotations()
.addKeepMainRule(TestClass.class)
.addProgramClasses(TestClass.class, A.class, B.class)
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSubclassKeepsSuperTest.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSubclassKeepsSuperTest.java
index 5e7786f..12d1f35 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSubclassKeepsSuperTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptSubclassKeepsSuperTest.java
@@ -7,8 +7,8 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.NeverPropagateValue;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersBuilder;
@@ -47,7 +47,7 @@
.enableGraphInspector()
.enableInliningAnnotations()
.enableMemberValuePropagationAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.enableNeverClassInliningAnnotations()
.addProgramClasses(CLASS, Foo.class, Bar.class)
.addKeepMainRule(CLASS)
@@ -66,7 +66,7 @@
barClass.assertPresent().assertKeptBy(fooClass);
}
- @NeverMerge
+ @NoVerticalClassMerging
public abstract static class Bar {}
@NeverClassInline
diff --git a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptViaClassInitializerTestRunner.java b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptViaClassInitializerTestRunner.java
index 366a97e..4d385a0 100644
--- a/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptViaClassInitializerTestRunner.java
+++ b/src/test/java/com/android/tools/r8/shaking/keptgraph/KeptViaClassInitializerTestRunner.java
@@ -12,7 +12,6 @@
import static org.junit.Assume.assumeTrue;
import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverMerge;
import com.android.tools.r8.NeverPropagateValue;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
@@ -37,7 +36,6 @@
@RunWith(Parameterized.class)
public class KeptViaClassInitializerTestRunner extends TestBase {
- @NeverMerge
@NeverClassInline
public static class A {
@@ -47,7 +45,6 @@
}
}
- @NeverMerge
@NeverClassInline
public enum T {
A(A::new);
diff --git a/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideTest.java b/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideTest.java
index 0f8a6bd..bc12cfc 100644
--- a/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/librarymethodoverride/LibraryMethodOverrideTest.java
@@ -9,7 +9,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import com.android.tools.r8.NeverClassInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.TestParametersCollection;
@@ -42,7 +42,7 @@
.addKeepMainRule(TestClass.class)
.addOptionsModification(options -> options.enableTreeShakingOfLibraryMethodOverrides = true)
.enableNeverClassInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::verifyOutput)
@@ -95,7 +95,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
static class EscapesIndirectly {
@Override
@@ -106,7 +106,7 @@
static class EscapesIndirectlySub extends EscapesIndirectly {}
- @NeverMerge
+ @NoVerticalClassMerging
static class EscapesIndirectlyWithOverride {
@Override
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/MethodsTestBase.java b/src/test/java/com/android/tools/r8/shaking/methods/MethodsTestBase.java
index 7adb908..07be6e7 100644
--- a/src/test/java/com/android/tools/r8/shaking/methods/MethodsTestBase.java
+++ b/src/test/java/com/android/tools/r8/shaking/methods/MethodsTestBase.java
@@ -4,7 +4,7 @@
package com.android.tools.r8.shaking.methods;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -30,7 +30,7 @@
List<String> keepRules, BiConsumer<CodeInspector, Shrinker> inspector, String expected)
throws Throwable {
testForR8(Backend.DEX)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addProgramClasses(getClasses())
.addKeepRules(keepRules)
.compile()
@@ -43,7 +43,7 @@
List<String> keepRules, BiConsumer<CodeInspector, Shrinker> inspector, String expected)
throws Throwable {
testForR8Compat(Backend.DEX)
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.addProgramClasses(getClasses())
.addKeepRules(keepRules)
.compile()
@@ -57,7 +57,7 @@
throws Throwable {
testForProguard()
.addProgramClasses(getClasses())
- .addProgramClasses(NeverMerge.class)
+ .addProgramClasses(NoVerticalClassMerging.class)
.addKeepRules(keepRules)
.compile()
.inspect(i -> inspector.accept(i, Shrinker.Proguard))
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/abst/AbstractMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/methods/abst/AbstractMethodsTest.java
index 8944bb6..9fe2a68 100644
--- a/src/test/java/com/android/tools/r8/shaking/methods/abst/AbstractMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/methods/abst/AbstractMethodsTest.java
@@ -9,7 +9,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.shaking.methods.MethodsTestBase;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -20,17 +20,17 @@
import java.util.Set;
import org.junit.Test;
-@NeverMerge
+@NoVerticalClassMerging
abstract class Super {
public abstract void m1();
}
-@NeverMerge
+@NoVerticalClassMerging
abstract class Sub extends Super {
public abstract void m2();
}
-@NeverMerge
+@NoVerticalClassMerging
class SubSub extends Sub {
public void m1() {}
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/pblc/PublicMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/methods/pblc/PublicMethodsTest.java
index ddeff6d..2ce8046 100644
--- a/src/test/java/com/android/tools/r8/shaking/methods/pblc/PublicMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/methods/pblc/PublicMethodsTest.java
@@ -8,7 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.shaking.methods.MethodsTestBase;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -18,17 +18,17 @@
import java.util.Set;
import org.junit.Test;
-@NeverMerge
+@NoVerticalClassMerging
class Super {
public void m1() {}
}
-@NeverMerge
+@NoVerticalClassMerging
class Sub extends Super {
public void m2() {}
}
-@NeverMerge
+@NoVerticalClassMerging
class SubSub extends Sub {
public void m3() {}
}
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/pckg/PackageMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/methods/pckg/PackageMethodsTest.java
index ef4e527..e2f3886 100644
--- a/src/test/java/com/android/tools/r8/shaking/methods/pckg/PackageMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/methods/pckg/PackageMethodsTest.java
@@ -8,7 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.shaking.methods.MethodsTestBase;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
@@ -17,17 +17,17 @@
import java.util.Set;
import org.junit.Test;
-@NeverMerge
+@NoVerticalClassMerging
class Super {
void m1() {}
}
-@NeverMerge
+@NoVerticalClassMerging
class Sub extends Super {
void m2() {}
}
-@NeverMerge
+@NoVerticalClassMerging
class SubSub extends Sub {
void m3() {}
}
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/prvt/PrivateMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/methods/prvt/PrivateMethodsTest.java
index 98be19a..bb5b668 100644
--- a/src/test/java/com/android/tools/r8/shaking/methods/prvt/PrivateMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/methods/prvt/PrivateMethodsTest.java
@@ -8,7 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.shaking.methods.MethodsTestBase;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -18,17 +18,17 @@
import java.util.Set;
import org.junit.Test;
-@NeverMerge
+@NoVerticalClassMerging
class Super {
private void m1() {}
}
-@NeverMerge
+@NoVerticalClassMerging
class Sub extends Super {
private void m2() {}
}
-@NeverMerge
+@NoVerticalClassMerging
class SubSub extends Sub {
private void m3() {}
}
diff --git a/src/test/java/com/android/tools/r8/shaking/methods/shadow/ShadowMethodsTest.java b/src/test/java/com/android/tools/r8/shaking/methods/shadow/ShadowMethodsTest.java
index e10cca9..5f8bc2e 100644
--- a/src/test/java/com/android/tools/r8/shaking/methods/shadow/ShadowMethodsTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/methods/shadow/ShadowMethodsTest.java
@@ -8,7 +8,7 @@
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertEquals;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.shaking.methods.MethodsTestBase;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.codeinspector.ClassSubject;
@@ -17,19 +17,19 @@
import java.util.Collection;
import org.junit.Test;
-@NeverMerge
+@NoVerticalClassMerging
class Super {
public void m1() {}
private void m2() {}
}
-@NeverMerge
+@NoVerticalClassMerging
class Sub extends Super {
public void m1() {}
private void m2() {}
}
-@NeverMerge
+@NoVerticalClassMerging
class SubSub extends Sub {
public void m1() {}
public void m2() {}
diff --git a/src/test/java/com/android/tools/r8/shaking/testrules/A.java b/src/test/java/com/android/tools/r8/shaking/testrules/A.java
index cf97eeb..4536cd9 100644
--- a/src/test/java/com/android/tools/r8/shaking/testrules/A.java
+++ b/src/test/java/com/android/tools/r8/shaking/testrules/A.java
@@ -4,9 +4,9 @@
package com.android.tools.r8.shaking.testrules;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoStaticClassMerging;
-@NeverMerge
+@NoStaticClassMerging
public class A {
public static int m(int a, int b) {
diff --git a/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java b/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java
index 382ee13..41533ec 100644
--- a/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/testrules/ForceInlineTest.java
@@ -42,6 +42,7 @@
return testForR8(parameters.getBackend())
.addProgramClasses(Main.class, A.class, B.class, C.class)
.addKeepRules(proguardConfiguration)
+ .enableNoStaticClassMergingAnnotations()
.enableProguardTestOptions()
.compile()
.inspector();
@@ -53,7 +54,6 @@
runTest(
ImmutableList.of(
"-keep class **.Main { *; }",
- "-nevermerge @com.android.tools.r8.NeverMerge class *",
"-neverinline class *{ @com.android.tools.r8.NeverInline <methods>;}",
"-dontobfuscate"));
@@ -84,7 +84,6 @@
"-neverinline class **.A { method(); }",
"-neverinline class **.B { method(); }",
"-keep class **.Main { *; }",
- "-nevermerge @com.android.tools.r8.NeverMerge class *",
"-neverinline class *{ @com.android.tools.r8.NeverInline <methods>;}",
"-dontobfuscate"));
@@ -112,7 +111,6 @@
"-forceinline class **.A { int m(int, int); }",
"-forceinline class **.B { int m(int, int); }",
"-keep class **.Main { *; }",
- "-nevermerge @com.android.tools.r8.NeverMerge class *",
"-neverinline class *{ @com.android.tools.r8.NeverInline <methods>;}",
"-dontobfuscate"));
@@ -130,7 +128,6 @@
ImmutableList.of(
"-forceinline class **.A { int x(); }",
"-keep class **.Main { *; }",
- "-nevermerge @com.android.tools.r8.NeverMerge class *",
"-dontobfuscate"));
fail("Force inline of non-inlinable method succeeded");
} catch (Throwable t) {
diff --git a/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingOverriddenMethodTest.java b/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingOverriddenMethodTest.java
index 39d3aaf..79c5edc 100644
--- a/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingOverriddenMethodTest.java
+++ b/src/test/java/com/android/tools/r8/shaking/whyareyoukeeping/WhyAreYouKeepingOverriddenMethodTest.java
@@ -9,7 +9,7 @@
import com.android.tools.r8.NeverClassInline;
import com.android.tools.r8.NeverInline;
-import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.NoVerticalClassMerging;
import com.android.tools.r8.TestBase;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.references.Reference;
@@ -53,7 +53,7 @@
"-whyareyoukeeping class **.*$" + targetClass.getSimpleName() + " { void gone(); }")
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.minification(minification)
.setMinApi(AndroidApiLevel.B)
// Redirect the compilers stdout to intercept the '-whyareyoukeeping' output
@@ -71,7 +71,7 @@
.addKeepMainRule(main)
.enableNeverClassInliningAnnotations()
.enableInliningAnnotations()
- .enableMergeAnnotations()
+ .enableNoVerticalClassMergingAnnotations()
.minification(minification)
.setMinApi(AndroidApiLevel.B)
.setKeptGraphConsumer(graphConsumer)
@@ -114,7 +114,7 @@
testViaConsumer(TestMain2.class, Itf.class, Impl.class);
}
- @NeverMerge
+ @NoVerticalClassMerging
static class Base {
@NeverInline
public void gone() {
@@ -137,7 +137,7 @@
}
}
- @NeverMerge
+ @NoVerticalClassMerging
interface Itf {
void gone();
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
index 04a8671..fe4d4d9 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentClassSubject.java
@@ -12,6 +12,7 @@
import java.util.List;
import java.util.function.Consumer;
import kotlinx.metadata.jvm.KotlinClassMetadata;
+import org.junit.rules.TemporaryFolder;
public class AbsentClassSubject extends ClassSubject {
@@ -96,7 +97,7 @@
@Override
public String getOriginalName() {
- return null;
+ return reference.getTypeName();
}
@Override
@@ -190,7 +191,12 @@
}
@Override
- public void disassembleUsingJavap(boolean verbose) throws Exception {
+ public String disassembleUsingJavap(boolean verbose) throws Exception {
throw new Unreachable("Cannot disassembly an absent class");
}
+
+ @Override
+ public String asmify(TemporaryFolder tempFolder, boolean debug) throws Exception {
+ throw new Unreachable("Cannot asmify an absent class");
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
index c62f945..f81dffd 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/AbsentMethodSubject.java
@@ -74,6 +74,11 @@
}
@Override
+ public boolean isSynchronized() {
+ throw new Unreachable("Cannot determine if an absent method is synchronized");
+ }
+
+ @Override
public boolean isInstanceInitializer() {
throw new Unreachable("Cannot determine if an absent method is an instance initializer");
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
index 6cf80fb..4e6a3f5 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/CfInstructionSubject.java
@@ -351,7 +351,6 @@
return instruction instanceof CfArrayStore;
}
-
@Override
public int size() {
// TODO(b/122302789): CfInstruction#getSize()
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
index d3c1ecc..96b0d0c 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/ClassSubject.java
@@ -25,6 +25,7 @@
import java.util.function.Consumer;
import java.util.function.Predicate;
import kotlinx.metadata.jvm.KotlinClassMetadata;
+import org.junit.rules.TemporaryFolder;
public abstract class ClassSubject extends Subject {
@@ -217,5 +218,7 @@
public abstract ClassNamingForNameMapper getNaming();
- public abstract void disassembleUsingJavap(boolean verbose) throws Exception;
+ public abstract String disassembleUsingJavap(boolean verbose) throws Exception;
+
+ public abstract String asmify(TemporaryFolder tempFolder, boolean debug) throws Exception;
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
index 8d925da..dbdff3d 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundClassSubject.java
@@ -30,10 +30,14 @@
import com.android.tools.r8.references.ClassReference;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.StringUtils;
+import com.android.tools.r8.utils.ZipUtils;
+import java.io.File;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import kotlinx.metadata.jvm.KotlinClassMetadata;
+import org.junit.rules.TemporaryFolder;
public class FoundClassSubject extends ClassSubject {
@@ -191,7 +195,7 @@
public FieldSubject uniqueFieldWithName(String name) {
FieldSubject fieldSubject = null;
for (FoundFieldSubject candidate : allFields()) {
- if (candidate.getOriginalName().equals(name)) {
+ if (candidate.getOriginalName(false).equals(name)) {
assert fieldSubject == null;
fieldSubject = candidate;
}
@@ -424,7 +428,7 @@
}
@Override
- public void disassembleUsingJavap(boolean verbose) throws Exception {
+ public String disassembleUsingJavap(boolean verbose) throws Exception {
assert dexClass.origin != null;
List<String> command = new ArrayList<>();
command.add(
@@ -442,5 +446,34 @@
ProcessResult processResult = ToolHelper.runProcess(new ProcessBuilder(command));
assert processResult.exitCode == 0;
System.out.println(processResult.stdout);
+ return processResult.stdout;
+ }
+
+ @Override
+ public String asmify(TemporaryFolder tempFolder, boolean debug) throws Exception {
+ assert dexClass.origin != null;
+ List<String> parts = dexClass.origin.parts();
+ assert parts.size() == 2;
+ String directory = parts.get(0);
+ String fileName = parts.get(1);
+ if (directory.endsWith(".jar") || directory.endsWith(".zip")) {
+ File tempOut = tempFolder.newFolder();
+ ZipUtils.unzip(directory, tempOut);
+ directory = tempOut.getAbsolutePath();
+ }
+ List<String> command = new ArrayList<>();
+ command.add(
+ CfRuntime.getCheckedInJdk9().getJavaHome().resolve("bin").resolve("java").toString());
+ command.add("-cp");
+ command.add(ToolHelper.ASM_JAR + ":" + ToolHelper.ASM_UTIL_JAR);
+ command.add("org.objectweb.asm.util.ASMifier");
+ if (!debug) {
+ command.add("-debug");
+ }
+ command.add(Paths.get(directory, fileName).toString());
+ ProcessResult processResult = ToolHelper.runProcess(new ProcessBuilder(command));
+ assert processResult.exitCode == 0;
+ System.out.println(processResult.stdout);
+ return processResult.stdout;
}
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
index 299a6c0..536aa5e3 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/FoundMethodSubject.java
@@ -122,6 +122,11 @@
}
@Override
+ public boolean isSynchronized() {
+ return dexMethod.accessFlags.isSynchronized();
+ }
+
+ @Override
public boolean isInstanceInitializer() {
return dexMethod.isInstanceInitializer();
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
index f2b7fe3..04f007b 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/Matchers.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.utils.codeinspector;
+import static org.hamcrest.CoreMatchers.not;
+
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AccessFlags;
import com.android.tools.r8.graph.DexClass;
@@ -107,7 +109,7 @@
@Override
public void describeTo(final Description description) {
- description.appendText(" present");
+ description.appendText("present");
}
@Override
@@ -660,4 +662,11 @@
return getClassName() + "." + getMethodName() + "(" + filename + ":" + originalPosition + ")";
}
}
+
+ public static <T> Matcher<T> notIf(Matcher<T> matcher, boolean condition) {
+ if (condition) {
+ return not(matcher);
+ }
+ return matcher;
+ }
}
diff --git a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
index 690838d..3c86361 100644
--- a/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
+++ b/src/test/java/com/android/tools/r8/utils/codeinspector/MethodSubject.java
@@ -25,6 +25,8 @@
public abstract boolean isBridge();
+ public abstract boolean isSynchronized();
+
public abstract boolean isInstanceInitializer();
public abstract boolean isClassInitializer();
diff --git a/tools/test.py b/tools/test.py
index 5bc9d6c..fbc1985 100755
--- a/tools/test.py
+++ b/tools/test.py
@@ -138,6 +138,9 @@
result.add_option('--worktree',
default=False, action='store_true',
help='Tests are run in worktree and should not use gradle user home.')
+ result.add_option('--horizontal-class-merging', '--horizontal_class_merging',
+ help='Enable horizontal class merging.',
+ default=False, action='store_true')
result.add_option('--runtimes',
default=None,
help='Test parameter runtimes to use, separated by : (eg, none:jdk9).'