Merge commit '072f610d7f11a5d9f6614e5d1c9e847383db5efe' into dev-release
diff --git a/.gitignore b/.gitignore
index aa4c9ae..b382c4f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,7 +3,6 @@
!third_party/gmscore/*.sha1
!third_party/internal/*.sha1
!third_party/nest/*.sha1
-!third_party/photos/*.sha1
!third_party/proguard/*.sha1
!third_party/youtube/*sha1
#*#
@@ -125,7 +124,6 @@
third_party/openjdk/openjdk-rt-1.8.tar.gz
third_party/opensource_apps
third_party/opensource_apps.tar.gz
-third_party/photos/*
third_party/proguard/*
third_party/proguardsettings.tar.gz
third_party/proguardsettings/
diff --git a/build.gradle b/build.gradle
index 2e2132d..730d291 100644
--- a/build.gradle
+++ b/build.gradle
@@ -425,7 +425,6 @@
"gmscore/v7",
"gmscore/v8",
"nest/nest_20180926_7c6cfb",
- "photos/2017-06-06",
"proguard/proguard_internal_159423826",
"proguardsettings",
"proto",
diff --git a/src/main/java/com/android/tools/r8/D8.java b/src/main/java/com/android/tools/r8/D8.java
index 99ff6a7..3651899 100644
--- a/src/main/java/com/android/tools/r8/D8.java
+++ b/src/main/java/com/android/tools/r8/D8.java
@@ -165,8 +165,9 @@
throws IOException {
PrefixRewritingMapper rewritePrefix =
options.desugaredLibraryConfiguration.createPrefixRewritingMapper(options);
- LazyLoadedDexApplication app = new ApplicationReader(inputApp, options, timing).read(executor);
- AppInfo appInfo = AppInfo.createInitialAppInfo(app);
+ ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing);
+ LazyLoadedDexApplication app = applicationReader.read(executor);
+ AppInfo appInfo = AppInfo.createInitialAppInfo(app, applicationReader.readMainDexClasses(app));
return AppView.createForD8(appInfo, rewritePrefix);
}
@@ -280,13 +281,15 @@
DexApplication app =
rewriteNonDexInputs(
appView, inputApp, options, executor, timing, appView.appInfo().app());
- appView.setAppInfo(new AppInfo(app, appView.appInfo().getSyntheticItems().commit(app)));
+ appView.setAppInfo(
+ new AppInfo(
+ app,
+ appView.appInfo().getMainDexClasses(),
+ appView.appInfo().getSyntheticItems().commit(app)));
namingLens = NamingLens.getIdentityLens();
}
new ApplicationWriter(
- appView.appInfo().app(),
appView,
- options,
marker == null ? null : ImmutableList.copyOf(markers),
GraphLens.getIdentityLens(),
InitClassLens.getDefault(),
@@ -307,7 +310,7 @@
}
private static DexApplication rewriteNonDexInputs(
- AppView<?> appView,
+ AppView<AppInfo> appView,
AndroidApp inputApp,
InternalOptions options,
ExecutorService executor,
@@ -333,6 +336,11 @@
}
}
DexApplication cfApp = app.builder().replaceProgramClasses(nonDexProgramClasses).build();
+ appView.setAppInfo(
+ new AppInfo(
+ cfApp,
+ appView.appInfo().getMainDexClasses(),
+ appView.appInfo().getSyntheticItems().commit(cfApp)));
ConvertedCfFiles convertedCfFiles = new ConvertedCfFiles();
NamingLens prefixRewritingNamingLens =
PrefixRewritingNamingLens.createPrefixRewritingNamingLens(appView);
@@ -340,9 +348,7 @@
.run(appView.appInfo().classes(), executor);
new KotlinMetadataRewriter(appView, prefixRewritingNamingLens).runForD8(executor);
new ApplicationWriter(
- cfApp,
appView,
- options,
null,
GraphLens.getIdentityLens(),
InitClassLens.getDefault(),
diff --git a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
index 49ab77b..4d1c0dc 100644
--- a/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
+++ b/src/main/java/com/android/tools/r8/DexFileMergerHelper.java
@@ -85,13 +85,17 @@
try {
try {
Timing timing = new Timing("DexFileMerger");
+ ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing);
DexApplication app =
- new ApplicationReader(inputApp, options, timing)
- .read(
- null,
- executor,
- new DexFileMergerHelper(inputOrdering)::keepFirstProgramClassConflictResolver);
- AppView<AppInfo> appView = AppView.createForD8(AppInfo.createInitialAppInfo(app));
+ applicationReader.read(
+ null,
+ executor,
+ new DexFileMergerHelper(inputOrdering)::keepFirstProgramClassConflictResolver);
+
+ AppView<AppInfo> appView =
+ AppView.createForD8(
+ AppInfo.createInitialAppInfo(app, applicationReader.readMainDexClasses(app)));
+
D8.optimize(appView, options, timing, executor);
List<Marker> markers = appView.dexItemFactory().extractMarkers();
@@ -99,9 +103,7 @@
assert !options.hasMethodsFilter();
ApplicationWriter writer =
new ApplicationWriter(
- appView.appInfo().app(),
- null,
- options,
+ appView,
markers,
GraphLens.getIdentityLens(),
InitClassLens.getDefault(),
diff --git a/src/main/java/com/android/tools/r8/DexSplitterHelper.java b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
index 9935d84..8b5d011 100644
--- a/src/main/java/com/android/tools/r8/DexSplitterHelper.java
+++ b/src/main/java/com/android/tools/r8/DexSplitterHelper.java
@@ -19,6 +19,7 @@
import com.android.tools.r8.graph.LazyLoadedDexApplication;
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.utils.ExceptionUtils;
import com.android.tools.r8.utils.FeatureClassMapping;
import com.android.tools.r8.utils.FeatureClassMapping.FeatureMappingException;
@@ -71,8 +72,10 @@
try {
Timing timing = new Timing("DexSplitter");
- DexApplication app =
- new ApplicationReader(command.getInputApp(), options, timing).read(null, executor);
+ ApplicationReader applicationReader =
+ new ApplicationReader(command.getInputApp(), options, timing);
+ DexApplication app = applicationReader.read(executor);
+ MainDexClasses mainDexClasses = applicationReader.readMainDexClasses(app);
List<Marker> markers = app.dexItemFactory.extractMarkers();
@@ -83,13 +86,20 @@
Map<String, LazyLoadedDexApplication.Builder> applications =
getDistribution(app, featureClassMapping, mapper);
for (Entry<String, LazyLoadedDexApplication.Builder> entry : applications.entrySet()) {
+ String feature = entry.getKey();
DexApplication featureApp = entry.getValue().build();
assert !options.hasMethodsFilter();
- // Run d8 optimize to ensure jumbo strings are handled.
- AppInfo appInfo = AppInfo.createInitialAppInfo(featureApp);
+ // If this is the base, we add the main dex list.
+ AppInfo appInfo =
+ feature.equals(featureClassMapping.getBaseName())
+ ? AppInfo.createInitialAppInfo(featureApp, mainDexClasses)
+ : AppInfo.createInitialAppInfo(featureApp);
AppView<AppInfo> appView = AppView.createForD8(appInfo);
+
+ // Run d8 optimize to ensure jumbo strings are handled.
D8.optimize(appView, options, timing, executor);
+
// We create a specific consumer for each split.
Path outputDir = Paths.get(output).resolve(entry.getKey());
if (!Files.exists(outputDir)) {
@@ -99,9 +109,7 @@
try {
new ApplicationWriter(
- appView.appInfo().app(),
appView,
- options,
markers,
GraphLens.getIdentityLens(),
InitClassLens.getDefault(),
@@ -134,10 +142,6 @@
LazyLoadedDexApplication.Builder featureApplication = applications.get(feature);
if (featureApplication == null) {
featureApplication = DexApplication.builder(app.options, app.timing);
- // If this is the base, we add the main dex list.
- if (feature.equals(featureClassMapping.getBaseName())) {
- featureApplication.addToMainDexList(app.mainDexList);
- }
applications.put(feature, featureApplication);
}
featureApplication.addProgramClass(clazz);
diff --git a/src/main/java/com/android/tools/r8/ExtractMarker.java b/src/main/java/com/android/tools/r8/ExtractMarker.java
index c8d6295..9492e12 100644
--- a/src/main/java/com/android/tools/r8/ExtractMarker.java
+++ b/src/main/java/com/android/tools/r8/ExtractMarker.java
@@ -103,8 +103,7 @@
InternalOptions options = new InternalOptions();
options.skipReadingDexCode = true;
options.minApiLevel = AndroidApiLevel.P.getLevel();
- DexApplication dexApp =
- new ApplicationReader(app, options, new Timing("ExtractMarker")).read();
+ DexApplication dexApp = new ApplicationReader(app, options, new Timing("ExtractMarker")).read();
return dexApp.dexItemFactory.extractMarkers();
}
diff --git a/src/main/java/com/android/tools/r8/GenerateLintFiles.java b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
index 8144903..74da57f 100644
--- a/src/main/java/com/android/tools/r8/GenerateLintFiles.java
+++ b/src/main/java/com/android/tools/r8/GenerateLintFiles.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.ir.desugar.DesugaredLibraryConfiguration;
import com.android.tools.r8.ir.desugar.DesugaredLibraryConfigurationParser;
@@ -284,7 +285,7 @@
// Build a plain text file with the desugared APIs.
List<String> desugaredApisSignatures = new ArrayList<>();
- DexApplication.Builder builder = DexApplication.builder(options, Timing.empty());
+ LazyLoadedDexApplication.Builder builder = DexApplication.builder(options, Timing.empty());
supportedMethods.supportedMethods.forEach(
(clazz, methods) -> {
String classBinaryName =
@@ -310,8 +311,7 @@
lintFile(compilationApiLevel, minApiLevel, ".txt"), desugaredApisSignatures);
// Write a header jar with the desugared APIs.
- AppInfo appInfo = AppInfo.createInitialAppInfo(builder.build());
- AppView<?> appView = AppView.createForD8(appInfo);
+ AppView<?> appView = AppView.createForD8(AppInfo.createInitialAppInfo(builder.build()));
CfApplicationWriter writer =
new CfApplicationWriter(
appView,
diff --git a/src/main/java/com/android/tools/r8/GenerateMainDexList.java b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
index 243b37a..04479b1 100644
--- a/src/main/java/com/android/tools/r8/GenerateMainDexList.java
+++ b/src/main/java/com/android/tools/r8/GenerateMainDexList.java
@@ -16,8 +16,8 @@
import com.android.tools.r8.graph.SubtypingInfo;
import com.android.tools.r8.shaking.Enqueuer;
import com.android.tools.r8.shaking.EnqueuerFactory;
-import com.android.tools.r8.shaking.MainDexClasses;
import com.android.tools.r8.shaking.MainDexListBuilder;
+import com.android.tools.r8.shaking.MainDexTracingResult;
import com.android.tools.r8.shaking.RootSetBuilder;
import com.android.tools.r8.shaking.RootSetBuilder.RootSet;
import com.android.tools.r8.shaking.WhyAreYouKeepingConsumer;
@@ -70,10 +70,10 @@
EnqueuerFactory.createForMainDexTracing(appView, subtypingInfo, graphConsumer);
Set<DexProgramClass> liveTypes = enqueuer.traceMainDex(mainDexRootSet, executor, timing);
// LiveTypes is the result.
- MainDexClasses mainDexClasses = new MainDexListBuilder(liveTypes, appView).run();
+ MainDexTracingResult mainDexTracingResult = new MainDexListBuilder(liveTypes, appView).run();
List<String> result =
- mainDexClasses.getClasses().stream()
+ mainDexTracingResult.getClasses().stream()
.map(c -> c.toSourceString().replace('.', '/') + ".class")
.sorted()
.collect(Collectors.toList());
@@ -88,7 +88,7 @@
() -> {
ArrayList<DexProgramClass> classes = new ArrayList<>();
// TODO(b/131668850): This is not a deterministic order!
- mainDexClasses
+ mainDexTracingResult
.getClasses()
.forEach(
type -> {
diff --git a/src/main/java/com/android/tools/r8/JarSizeCompare.java b/src/main/java/com/android/tools/r8/JarSizeCompare.java
index 83261a3..15e29fa 100644
--- a/src/main/java/com/android/tools/r8/JarSizeCompare.java
+++ b/src/main/java/com/android/tools/r8/JarSizeCompare.java
@@ -53,7 +53,8 @@
+ " --input <name2> <input2.jar> [<map2.txt>] ...\n"
+ "\n"
+ "JarSizeCompare outputs the class, method, field sizes of the given JAR files.\n"
- + "For each input, a ProGuard map can be passed that is used to resolve minified names.\n";
+ + "For each input, a ProGuard map can be passed that is used to resolve minified"
+ + " names.\n";
private static final ImmutableMap<String, String> R8_RELOCATIONS =
ImmutableMap.<String, String>builder()
diff --git a/src/main/java/com/android/tools/r8/PrintClassList.java b/src/main/java/com/android/tools/r8/PrintClassList.java
index 40cdf2e..73cb04d 100644
--- a/src/main/java/com/android/tools/r8/PrintClassList.java
+++ b/src/main/java/com/android/tools/r8/PrintClassList.java
@@ -45,8 +45,7 @@
new ApplicationReader(builder.build(), new InternalOptions(), new Timing("PrintClassList"))
.read(
proguardMapFile == null ? null : StringResource.fromFile(proguardMapFile),
- executorService
- );
+ executorService);
ClassNameMapper map = application.getProguardMap();
for (DexProgramClass clazz : application.classes()) {
System.out.print(maybeDeobfuscateType(map, clazz.type));
diff --git a/src/main/java/com/android/tools/r8/PrintUses.java b/src/main/java/com/android/tools/r8/PrintUses.java
index 47ed5a0..7ffc5ae 100644
--- a/src/main/java/com/android/tools/r8/PrintUses.java
+++ b/src/main/java/com/android/tools/r8/PrintUses.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.graph.ResolutionResult;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.desugar.LambdaDescriptor;
+import com.android.tools.r8.shaking.MainDexClasses;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.StringUtils;
@@ -349,7 +350,9 @@
InternalOptions options = new InternalOptions();
application =
new ApplicationReader(inputApp, options, new Timing("PrintUses")).read().toDirect();
- appInfo = AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(application);
+ appInfo =
+ AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
+ application, 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 3a9b0d9..7b94e97 100644
--- a/src/main/java/com/android/tools/r8/R8.java
+++ b/src/main/java/com/android/tools/r8/R8.java
@@ -91,6 +91,7 @@
import com.android.tools.r8.shaking.EnqueuerFactory;
import com.android.tools.r8.shaking.MainDexClasses;
import com.android.tools.r8.shaking.MainDexListBuilder;
+import com.android.tools.r8.shaking.MainDexTracingResult;
import com.android.tools.r8.shaking.ProguardClassFilter;
import com.android.tools.r8.shaking.ProguardConfigurationRule;
import com.android.tools.r8.shaking.ProguardConfigurationUtils;
@@ -231,9 +232,7 @@
.write(options.getClassFileConsumer());
} else {
new ApplicationWriter(
- appView.appInfo().app(),
appView,
- options,
// Ensure that the marker for this compilation is the first in the list.
ImmutableList.<Marker>builder().add(marker).addAll(markers).build(),
graphLens,
@@ -290,13 +289,14 @@
try {
AppView<AppInfoWithClassHierarchy> appView;
{
- DirectMappedDexApplication application =
- new ApplicationReader(inputApp, options, timing).read(executorService).toDirect();
+ ApplicationReader applicationReader = new ApplicationReader(inputApp, options, timing);
+ DirectMappedDexApplication application = applicationReader.read(executorService).toDirect();
+ MainDexClasses mainDexClasses = applicationReader.readMainDexClasses(application);
// Now that the dex-application is fully loaded, close any internal archive providers.
inputApp.closeInternalArchiveProviders();
- appView = AppView.createForR8(application);
+ appView = AppView.createForR8(application, mainDexClasses);
appView.setAppServices(AppServices.builder(appView).build());
}
@@ -451,7 +451,7 @@
// by certain optimizations to avoid introducing additional class references into main dex
// classes, as that can cause the final number of main dex methods to grow.
RootSet mainDexRootSet = null;
- MainDexClasses mainDexClasses = MainDexClasses.NONE;
+ MainDexTracingResult mainDexTracingResult = MainDexTracingResult.NONE;
if (!options.mainDexKeepRules.isEmpty()) {
assert appView.graphLens().isIdentityLens();
// Find classes which may have code executed before secondary dex files installation.
@@ -464,7 +464,7 @@
EnqueuerFactory.createForMainDexTracing(appView, subtypingInfo)
.traceMainDex(mainDexRootSet, executorService, timing);
// Calculate the automatic main dex list according to legacy multidex constraints.
- mainDexClasses = new MainDexListBuilder(mainDexBaseClasses, appView).run();
+ mainDexTracingResult = new MainDexListBuilder(mainDexBaseClasses, appView).run();
appView.appInfo().unsetObsolete();
}
@@ -523,7 +523,7 @@
if (options.enableStaticClassMerging) {
timing.begin("HorizontalStaticClassMerger");
StaticClassMerger staticClassMerger =
- new StaticClassMerger(appViewWithLiveness, options, mainDexClasses);
+ new StaticClassMerger(appViewWithLiveness, options, mainDexTracingResult);
NestedGraphLens lens = staticClassMerger.run();
appView.rewriteWithLens(lens);
timing.end();
@@ -536,7 +536,7 @@
appViewWithLiveness,
executorService,
timing,
- mainDexClasses);
+ mainDexTracingResult);
VerticalClassMergerGraphLens lens = verticalClassMerger.run();
if (lens != null) {
appView.setVerticallyMergedClasses(verticalClassMerger.getMergedClasses());
@@ -548,7 +548,7 @@
timing.begin("HorizontalClassMerger");
HorizontalClassMerger merger =
new HorizontalClassMerger(
- appViewWithLiveness, mainDexClasses, classMergingEnqueuerExtension);
+ appViewWithLiveness, mainDexTracingResult, classMergingEnqueuerExtension);
HorizontalClassMergerGraphLens lens = merger.run();
if (lens != null) {
appView.setHorizontallyMergedClasses(lens.getHorizontallyMergedClasses());
@@ -613,7 +613,7 @@
timing.begin("Create IR");
CfgPrinter printer = options.printCfg ? new CfgPrinter() : null;
try {
- IRConverter converter = new IRConverter(appView, timing, printer, mainDexClasses);
+ IRConverter converter = new IRConverter(appView, timing, printer, mainDexTracingResult);
DexApplication application = converter.optimize(executorService).asDirect();
appView.setAppInfo(appView.appInfo().rebuild(previous -> application));
} finally {
@@ -660,8 +660,8 @@
Set<DexProgramClass> mainDexBaseClasses =
enqueuer.traceMainDex(mainDexRootSet, executorService, timing);
// Calculate the automatic main dex list according to legacy multidex constraints.
- mainDexClasses = new MainDexListBuilder(mainDexBaseClasses, appView).run();
- final MainDexClasses finalMainDexClasses = mainDexClasses;
+ mainDexTracingResult = new MainDexListBuilder(mainDexBaseClasses, appView).run();
+ final MainDexTracingResult finalMainDexClasses = mainDexTracingResult;
processWhyAreYouKeepingAndCheckDiscarded(
mainDexRootSet,
@@ -772,9 +772,10 @@
.setClassesToRetainInnerClassAttributeFor(classesToRetainInnerClassAttributeFor)
.build(appView.withLiveness(), removedClasses)
.run();
- if (!mainDexClasses.isEmpty()) {
+ if (!mainDexTracingResult.isEmpty()) {
// Remove types that no longer exists from the computed main dex list.
- mainDexClasses = mainDexClasses.prunedCopy(appView.appInfo().withLiveness());
+ mainDexTracingResult =
+ mainDexTracingResult.prunedCopy(appView.appInfo().withLiveness());
}
// Synthesize fields for triggering class initializers.
@@ -785,7 +786,7 @@
}
if (appView.options().protoShrinking().isProtoShrinkingEnabled()) {
- IRConverter converter = new IRConverter(appView, timing, null, mainDexClasses);
+ IRConverter converter = new IRConverter(appView, timing, null, mainDexTracingResult);
// If proto shrinking is enabled, we need to reprocess every dynamicMethod(). This ensures
// that proto fields that have been removed by the second round of tree shaking are also
@@ -872,17 +873,7 @@
// Add automatic main dex classes to an eventual manual list of classes.
if (!options.mainDexKeepRules.isEmpty()) {
- MainDexClasses finalMainDexClasses = mainDexClasses;
- appView.setAppInfo(
- appView
- .appInfo()
- .rebuild(
- application ->
- application
- .builder()
- .addToMainDexList(finalMainDexClasses.getClasses())
- .build()
- .asDirect()));
+ appView.appInfo().getMainDexClasses().addAll(mainDexTracingResult);
}
// Validity checks.
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 80dd656..0dcca76 100644
--- a/src/main/java/com/android/tools/r8/bisect/Bisect.java
+++ b/src/main/java/com/android/tools/r8/bisect/Bisect.java
@@ -189,9 +189,7 @@
AndroidAppConsumers compatSink = new AndroidAppConsumers(options);
ApplicationWriter writer =
new ApplicationWriter(
- app,
AppView.createForD8(AppInfo.createInitialAppInfo(app)),
- options,
null,
null,
InitClassLens.getDefault(),
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
index b679a54..f128f76 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArithmeticBinop.java
@@ -5,14 +5,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -131,7 +134,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(getAsmOpcode());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
index 6510e23..5757b8c 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLength.java
@@ -4,13 +4,16 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -21,7 +24,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(Opcodes.ARRAYLENGTH);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
index a9d754e..7993e8e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayLoad.java
@@ -5,15 +5,18 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -58,7 +61,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(getLoadType());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
index 5e8c152..1c16397 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfArrayStore.java
@@ -5,14 +5,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.MemberType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -56,7 +59,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(getStoreType());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
index 7f6a380..e263d02 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCheckCast.java
@@ -5,15 +5,18 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.DexClassAndMethod;
+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.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -34,8 +37,15 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
- visitor.visitTypeInsn(Opcodes.CHECKCAST, lens.lookupInternalName(graphLens.lookupType(type)));
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ DexType rewrittenType = graphLens.lookupType(type);
+ visitor.visitTypeInsn(Opcodes.CHECKCAST, namingLens.lookupInternalName(rewrittenType));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
index 1163483..1eeb6b4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfCmp.java
@@ -5,9 +5,11 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Cmp;
import com.android.tools.r8.ir.code.Cmp.Bias;
import com.android.tools.r8.ir.code.NumericType;
@@ -15,6 +17,7 @@
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -81,7 +84,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(getAsmOpcode());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
index 37255ff..2bb2444 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstClass.java
@@ -6,14 +6,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexClassAndMethod;
+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.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -34,10 +37,13 @@
@Override
public void write(
- MethodVisitor visitor,
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
GraphLens graphLens,
InitClassLens initClassLens,
- NamingLens namingLens) {
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitLdcInsn(Type.getObjectType(getInternalName(graphLens, namingLens)));
}
@@ -52,10 +58,11 @@
}
private String getInternalName(GraphLens graphLens, NamingLens namingLens) {
- switch (type.toShorty()) {
+ DexType rewrittenType = graphLens.lookupType(type);
+ switch (rewrittenType.toShorty()) {
case '[':
case 'L':
- return namingLens.lookupInternalName(graphLens.lookupType(type));
+ return namingLens.lookupInternalName(rewrittenType);
case 'Z':
return "java/lang/Boolean/TYPE";
case 'B':
@@ -73,7 +80,7 @@
case 'D':
return "java/lang/Double/TYPE";
default:
- throw new Unreachable("Unexpected type in const-class: " + type);
+ throw new Unreachable("Unexpected type in const-class: " + rewrittenType);
}
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
index c5d52f2..d058eca 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodHandle.java
@@ -5,15 +5,18 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethodHandle;
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.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -33,8 +36,17 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
- visitor.visitLdcInsn(handle.toAsmHandle(lens));
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ DexMethodHandle rewrittenHandle =
+ rewriter.rewriteDexMethodHandle(
+ handle, MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, context);
+ visitor.visitLdcInsn(rewrittenHandle.toAsmHandle(namingLens));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
index 17577b9..e59a64e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstMethodType.java
@@ -5,14 +5,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -33,8 +36,15 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
- visitor.visitLdcInsn(Type.getType(type.toDescriptorString(lens)));
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ DexProto rewrittenType = rewriter.rewriteProto(getType());
+ visitor.visitLdcInsn(Type.getType(rewrittenType.toDescriptorString(namingLens)));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
index 1c5e970..e5740e7 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNull.java
@@ -4,13 +4,16 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -21,7 +24,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(Opcodes.ACONST_NULL);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
index b4e63a9..642eeb9 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstNumber.java
@@ -5,13 +5,16 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -58,7 +61,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
switch (type) {
case INT:
{
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
index 649f756..9037875 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfConstString.java
@@ -4,13 +4,16 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+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.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -44,7 +47,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitLdcInsn(string.toString());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
index 79e59db..bdc470f 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfDexItemBasedConstString.java
@@ -6,14 +6,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -50,7 +53,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
throw new Unreachable(
"CfDexItemBasedConstString instructions should always be rewritten into CfConstString");
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
index 32c8494..3cff4ee 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFieldInstruction.java
@@ -7,15 +7,18 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
+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.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -55,12 +58,18 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
- DexField newField = graphLens.lookupField(field);
- DexField newDeclaringField = graphLens.lookupField(declaringField);
- String owner = lens.lookupInternalName(newField.holder);
- String name = lens.lookupName(newDeclaringField).toString();
- String desc = lens.lookupDescriptor(newField.type).toString();
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ DexField rewrittenField = graphLens.lookupField(field);
+ DexField rewrittenDeclaringField = graphLens.lookupField(declaringField);
+ String owner = namingLens.lookupInternalName(rewrittenField.holder);
+ String name = namingLens.lookupName(rewrittenDeclaringField).toString();
+ String desc = namingLens.lookupDescriptor(rewrittenField.type).toString();
visitor.visitFieldInsn(opcode, owner, name, desc);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
index 152f9e9..f392338 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfFrame.java
@@ -12,9 +12,11 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -44,7 +46,7 @@
return Top.SINGLETON;
}
- abstract Object getTypeOpcode(NamingLens lens);
+ abstract Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens);
public boolean isWide() {
return false;
@@ -102,13 +104,14 @@
}
@Override
- Object getTypeOpcode(NamingLens lens) {
- if (type == DexItemFactory.nullValueType) {
+ Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
+ DexType rewrittenType = graphLens.lookupType(type);
+ if (rewrittenType == DexItemFactory.nullValueType) {
return Opcodes.NULL;
}
- switch (type.toShorty()) {
+ switch (rewrittenType.toShorty()) {
case 'L':
- return lens.lookupInternalName(type);
+ return namingLens.lookupInternalName(rewrittenType);
case 'I':
return Opcodes.INTEGER;
case 'F':
@@ -118,7 +121,7 @@
case 'D':
return Opcodes.DOUBLE;
default:
- throw new Unreachable("Unexpected value type: " + type);
+ throw new Unreachable("Unexpected value type: " + rewrittenType);
}
}
@@ -148,7 +151,7 @@
}
@Override
- Object getTypeOpcode(NamingLens lens) {
+ Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
return Opcodes.TOP;
}
@@ -171,7 +174,7 @@
}
@Override
- Object getTypeOpcode(NamingLens lens) {
+ Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
return label.getLabel();
}
@@ -190,7 +193,7 @@
private UninitializedThis() {}
@Override
- Object getTypeOpcode(NamingLens lens) {
+ Object getTypeOpcode(GraphLens graphLens, NamingLens namingLens) {
return Opcodes.UNINITIALIZED_THIS;
}
@@ -225,11 +228,17 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
int stackCount = computeStackCount();
- Object[] stackTypes = computeStackTypes(stackCount, lens);
+ Object[] stackTypes = computeStackTypes(stackCount, graphLens, namingLens);
int localsCount = computeLocalsCount();
- Object[] localsTypes = computeLocalsTypes(localsCount, lens);
+ Object[] localsTypes = computeLocalsTypes(localsCount, graphLens, namingLens);
visitor.visitFrame(F_NEW, localsCount, localsTypes, stackCount, stackTypes);
}
@@ -237,14 +246,14 @@
return stack.size();
}
- private Object[] computeStackTypes(int stackCount, NamingLens lens) {
+ private Object[] computeStackTypes(int stackCount, GraphLens graphLens, NamingLens namingLens) {
assert stackCount == stack.size();
if (stackCount == 0) {
return null;
}
Object[] stackTypes = new Object[stackCount];
for (int i = 0; i < stackCount; i++) {
- stackTypes[i] = stack.get(i).getTypeOpcode(lens);
+ stackTypes[i] = stack.get(i).getTypeOpcode(graphLens, namingLens);
}
return stackTypes;
}
@@ -266,7 +275,7 @@
return localsCount;
}
- private Object[] computeLocalsTypes(int localsCount, NamingLens lens) {
+ private Object[] computeLocalsTypes(int localsCount, GraphLens graphLens, NamingLens namingLens) {
if (localsCount == 0) {
return null;
}
@@ -275,7 +284,8 @@
int localIndex = 0;
for (int i = 0; i <= maxRegister; i++) {
FrameType type = locals.get(i);
- localsTypes[localIndex++] = type == null ? Opcodes.TOP : type.getTypeOpcode(lens);
+ localsTypes[localIndex++] =
+ type == null ? Opcodes.TOP : type.getTypeOpcode(graphLens, namingLens);
if (type != null && type.isWide()) {
i++;
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
index d38c0fe..0cd79d4 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfGoto.java
@@ -4,12 +4,15 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -46,7 +49,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitJumpInsn(Opcodes.GOTO, target.getLabel());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIf.java b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
index f64d79c..31497fd 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIf.java
@@ -5,15 +5,18 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.If.Type;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -71,7 +74,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitJumpInsn(getOpcode(), target.getLabel());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
index 1ee17b1..47cbcad 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIfCmp.java
@@ -5,15 +5,18 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.If.Type;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -71,7 +74,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitJumpInsn(getOpcode(), target.getLabel());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
index edba7b4..4a37601 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfIinc.java
@@ -4,13 +4,16 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -28,7 +31,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitIincInsn(var, increment);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
index afcae7d..b12d10e 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInitClass.java
@@ -6,14 +6,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.DexClassAndMethod;
import com.android.tools.r8.graph.DexField;
+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.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -39,11 +42,20 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
- DexField field = initClassLens.getInitClassField(clazz);
- String owner = lens.lookupInternalName(field.holder);
- String name = lens.lookupName(field).toString();
- String desc = lens.lookupDescriptor(field.type).toString();
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ // We intentionally apply the graph lens first, and then the init class lens, using the fact
+ // that the init class lens maps classes in the final program to fields in the final program.
+ DexType rewrittenClass = graphLens.lookupType(clazz);
+ DexField clinitField = initClassLens.getInitClassField(rewrittenClass);
+ String owner = namingLens.lookupInternalName(clinitField.holder);
+ String name = namingLens.lookupName(clinitField).toString();
+ String desc = namingLens.lookupDescriptor(clinitField.type).toString();
visitor.visitFieldInsn(OPCODE, owner, name, desc);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
index fc26a95..c34d576 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstanceOf.java
@@ -5,14 +5,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.DexClassAndMethod;
+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.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -43,8 +46,15 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
- visitor.visitTypeInsn(Opcodes.INSTANCEOF, lens.lookupInternalName(type));
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ DexType rewrittenType = graphLens.lookupType(getType());
+ visitor.visitTypeInsn(Opcodes.INSTANCEOF, namingLens.lookupInternalName(rewrittenType));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
index 16ef22f..da09f7b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInstruction.java
@@ -6,6 +6,7 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.ClasspathMethod;
import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
@@ -14,6 +15,7 @@
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -22,7 +24,13 @@
public abstract class CfInstruction {
public abstract void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens);
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor);
public abstract void print(CfPrinter printer);
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
index 3851031..4f21538 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvoke.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexClassAndMethod;
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.DexProto;
@@ -18,6 +19,7 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult;
import com.android.tools.r8.graph.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.Invoke;
import com.android.tools.r8.ir.code.Invoke.Type;
@@ -26,6 +28,7 @@
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -72,12 +75,20 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
- DexMethod newMethod = graphLens.lookupMethod(method);
- String owner = lens.lookupInternalName(newMethod.holder);
- String name = lens.lookupName(newMethod).toString();
- String desc = newMethod.proto.toDescriptorString(lens);
- visitor.visitMethodInsn(opcode, owner, name, desc, itf);
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ GraphLensLookupResult lookup =
+ graphLens.lookupMethod(method, context.getReference(), getInvokeType(context));
+ DexMethod rewrittenMethod = lookup.getMethod();
+ String owner = namingLens.lookupInternalName(rewrittenMethod.holder);
+ String name = namingLens.lookupName(rewrittenMethod).toString();
+ String desc = rewrittenMethod.proto.toDescriptorString(namingLens);
+ visitor.visitMethodInsn(lookup.getType().getCfOpcode(), owner, name, desc, itf);
}
@Override
@@ -87,25 +98,46 @@
@Override
void internalRegisterUse(UseRegistry registry, DexClassAndMethod context) {
- switch (opcode) {
- case Opcodes.INVOKEINTERFACE:
+ Type invokeType = getInvokeType(context);
+ switch (invokeType) {
+ case DIRECT:
+ registry.registerInvokeDirect(method);
+ break;
+ case INTERFACE:
registry.registerInvokeInterface(method);
break;
- case Opcodes.INVOKEVIRTUAL:
- registry.registerInvokeVirtual(method);
- break;
- case Opcodes.INVOKESPECIAL:
- if (method.name.toString().equals(Constants.INSTANCE_INITIALIZER_NAME)) {
- registry.registerInvokeDirect(method);
- } else if (method.holder == context.getHolderType()) {
- registry.registerInvokeDirect(method);
- } else {
- registry.registerInvokeSuper(method);
- }
- break;
- case Opcodes.INVOKESTATIC:
+ case STATIC:
registry.registerInvokeStatic(method);
break;
+ case SUPER:
+ registry.registerInvokeSuper(method);
+ break;
+ case VIRTUAL:
+ registry.registerInvokeVirtual(method);
+ break;
+ default:
+ throw new Unreachable("Unexpected invoke type " + invokeType);
+ }
+ }
+
+ private Invoke.Type getInvokeType(DexClassAndMethod context) {
+ switch (opcode) {
+ case Opcodes.INVOKEINTERFACE:
+ return Type.INTERFACE;
+
+ case Opcodes.INVOKEVIRTUAL:
+ return Type.VIRTUAL;
+
+ case Opcodes.INVOKESPECIAL:
+ if (method.name.toString().equals(Constants.INSTANCE_INITIALIZER_NAME)
+ || method.holder == context.getHolderType()) {
+ return Type.DIRECT;
+ }
+ return Type.SUPER;
+
+ case Opcodes.INVOKESTATIC:
+ return Type.STATIC;
+
default:
throw new Unreachable("unknown CfInvoke opcode " + opcode);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
index f57046b..a455305 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfInvokeDynamic.java
@@ -7,6 +7,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexCallSite;
import com.android.tools.r8.graph.DexClassAndMethod;
+import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethodHandle;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexString;
@@ -14,11 +15,13 @@
import com.android.tools.r8.graph.DexValue;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -38,17 +41,27 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
- DexMethodHandle bootstrapMethod = callSite.bootstrapMethod;
- List<DexValue> bootstrapArgs = callSite.bootstrapArgs;
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ DexCallSite rewrittenCallSite = rewriter.rewriteCallSite(callSite, context);
+ DexMethodHandle bootstrapMethod = rewrittenCallSite.bootstrapMethod;
+ List<DexValue> bootstrapArgs = rewrittenCallSite.bootstrapArgs;
Object[] bsmArgs = new Object[bootstrapArgs.size()];
for (int i = 0; i < bootstrapArgs.size(); i++) {
- bsmArgs[i] = decodeBootstrapArgument(bootstrapArgs.get(i), lens);
+ bsmArgs[i] = decodeBootstrapArgument(bootstrapArgs.get(i), namingLens);
}
- Handle bsmHandle = bootstrapMethod.toAsmHandle(lens);
- DexString methodName = lens.lookupMethodName(callSite);
+ Handle bsmHandle = bootstrapMethod.toAsmHandle(namingLens);
+ DexString methodName = namingLens.lookupMethodName(rewrittenCallSite);
visitor.visitInvokeDynamicInsn(
- methodName.toString(), callSite.methodProto.toDescriptorString(lens), bsmHandle, bsmArgs);
+ methodName.toString(),
+ rewrittenCallSite.methodProto.toDescriptorString(namingLens),
+ bsmHandle,
+ bsmArgs);
}
private Object decodeBootstrapArgument(DexValue value, NamingLens lens) {
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
index 88659de..47ee09b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfJsrRet.java
@@ -5,12 +5,15 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -31,7 +34,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
throw error();
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
index 19ba74a..b27fd00 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLabel.java
@@ -4,12 +4,15 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -44,7 +47,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitLabel(getLabel());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
index 80bb1da..17e0ecd 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLoad.java
@@ -5,14 +5,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -58,7 +61,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitVarInsn(getLoadType(), var);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
index 0f5bd4e..19a3bfe 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfLogicalBinop.java
@@ -5,14 +5,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -106,7 +109,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(getAsmOpcode());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
index ebefa78..24b580b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMonitor.java
@@ -4,14 +4,17 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Monitor.Type;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -32,7 +35,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(type == Type.ENTER ? Opcodes.MONITORENTER : Opcodes.MONITOREXIT);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
index 69a69af..33f4244 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfMultiANewArray.java
@@ -5,14 +5,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.DexClassAndMethod;
+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.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -39,8 +42,15 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
- visitor.visitMultiANewArrayInsn(lens.lookupInternalName(type), dimensions);
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ DexType rewrittenType = graphLens.lookupType(getType());
+ visitor.visitMultiANewArrayInsn(namingLens.lookupInternalName(rewrittenType), dimensions);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
index 32ef906..88274b3 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNeg.java
@@ -5,14 +5,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -33,7 +36,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(getAsmOpcode());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNew.java b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
index e0b8785..83b7e63 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNew.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNew.java
@@ -5,14 +5,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.graph.DexClassAndMethod;
+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.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -33,8 +36,15 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
- visitor.visitTypeInsn(Opcodes.NEW, lens.lookupInternalName(type));
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ DexType rewrittenType = graphLens.lookupType(getType());
+ visitor.visitTypeInsn(Opcodes.NEW, namingLens.lookupInternalName(rewrittenType));
}
@Override
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
index 6c3869b..3c9a746 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNewArray.java
@@ -6,15 +6,18 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexClassAndMethod;
+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.InitClassLens;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -58,21 +61,36 @@
}
}
- private String getElementInternalName(NamingLens lens) {
+ private String getElementInternalName(
+ DexItemFactory dexItemFactory, GraphLens graphLens, NamingLens namingLens) {
assert !type.isPrimitiveArrayType();
- String renamedArrayType = lens.lookupDescriptor(type).toString();
- assert renamedArrayType.charAt(0) == '[';
- String elementType = renamedArrayType.substring(1);
- return DescriptorUtils.descriptorToInternalName(elementType);
+ StringBuilder renamedElementDescriptor = new StringBuilder();
+ // Intentionally starting from 1 to get the element descriptor.
+ int numberOfLeadingSquareBrackets = getType().getNumberOfLeadingSquareBrackets();
+ for (int i = 1; i < numberOfLeadingSquareBrackets; i++) {
+ renamedElementDescriptor.append("[");
+ }
+ DexType baseType = getType().toBaseType(dexItemFactory);
+ DexType rewrittenBaseType = graphLens.lookupType(baseType);
+ renamedElementDescriptor.append(
+ namingLens.lookupDescriptor(rewrittenBaseType).toSourceString());
+ return DescriptorUtils.descriptorToInternalName(renamedElementDescriptor.toString());
}
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
if (type.isPrimitiveArrayType()) {
visitor.visitIntInsn(Opcodes.NEWARRAY, getPrimitiveTypeCode());
} else {
- visitor.visitTypeInsn(Opcodes.ANEWARRAY, getElementInternalName(lens));
+ visitor.visitTypeInsn(
+ Opcodes.ANEWARRAY, getElementInternalName(dexItemFactory, graphLens, namingLens));
}
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNop.java b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
index 18a2ae6..e2b6044 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNop.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNop.java
@@ -4,12 +4,15 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -20,7 +23,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(Opcodes.NOP);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
index 405fb42..ce3ab3b 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfNumberConversion.java
@@ -5,14 +5,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -43,7 +46,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(this.getAsmOpcode());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
index 70a3f07..e30be70 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfPosition.java
@@ -4,13 +4,16 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -28,7 +31,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitLineNumber(position.line, label.getLabel());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
index d66d6cf..c5198d1 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturn.java
@@ -5,14 +5,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -55,7 +58,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(getOpcode());
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
index 83b5e60..8f7bb37 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfReturnVoid.java
@@ -4,12 +4,15 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -25,7 +28,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(Opcodes.RETURN);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
index a4ecce6..a7a39b6 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStackInstruction.java
@@ -6,14 +6,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.CompilationError;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -77,7 +80,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(opcode.opcode);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfStore.java b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
index c3ce5db..d46d3a3 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfStore.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfStore.java
@@ -5,14 +5,17 @@
import com.android.tools.r8.cf.CfPrinter;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -58,7 +61,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitVarInsn(getStoreType(), var);
}
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
index 3a3c72e..edc5244 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfSwitch.java
@@ -4,13 +4,16 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -71,7 +74,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
Label[] labels = new Label[targets.size()];
for (int i = 0; i < targets.size(); i++) {
labels[i] = targets.get(i).getLabel();
diff --git a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
index 3b49cb0..aaa7280 100644
--- a/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
+++ b/src/main/java/com/android/tools/r8/cf/code/CfThrow.java
@@ -4,13 +4,16 @@
package com.android.tools.r8.cf.code;
import com.android.tools.r8.cf.CfPrinter;
+import com.android.tools.r8.graph.DexItemFactory;
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.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.CfState;
import com.android.tools.r8.ir.conversion.CfState.Slot;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
import com.android.tools.r8.naming.NamingLens;
@@ -26,7 +29,13 @@
@Override
public void write(
- MethodVisitor visitor, GraphLens graphLens, InitClassLens initClassLens, NamingLens lens) {
+ ProgramMethod context,
+ DexItemFactory dexItemFactory,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
visitor.visitInsn(Opcodes.ATHROW);
}
diff --git a/src/main/java/com/android/tools/r8/code/CheckCast.java b/src/main/java/com/android/tools/r8/code/CheckCast.java
index 569b358..6ca2dc5 100644
--- a/src/main/java/com/android/tools/r8/code/CheckCast.java
+++ b/src/main/java/com/android/tools/r8/code/CheckCast.java
@@ -5,9 +5,12 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.OffsetToObjectMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
public class CheckCast extends Format21c<DexType> {
@@ -39,8 +42,13 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- getType().collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexType rewritten = graphLens.lookupType(getType());
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstClass.java b/src/main/java/com/android/tools/r8/code/ConstClass.java
index 2f8f7db..ec8a13a 100644
--- a/src/main/java/com/android/tools/r8/code/ConstClass.java
+++ b/src/main/java/com/android/tools/r8/code/ConstClass.java
@@ -5,9 +5,12 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.OffsetToObjectMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
public class ConstClass extends Format21c<DexType> {
@@ -39,8 +42,13 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- getType().collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexType rewritten = graphLens.lookupType(getType());
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java b/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
index 8518946..75fc2dc 100644
--- a/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
+++ b/src/main/java/com/android/tools/r8/code/ConstMethodHandle.java
@@ -6,11 +6,14 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.graph.DexMethodHandle;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.OffsetToObjectMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -64,17 +67,33 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
- int index = BBBB.getOffset(mapping);
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ DexMethodHandle rewritten =
+ rewriter.rewriteDexMethodHandle(
+ getMethodHandle(), MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, context);
+ int index = rewritten.getOffset(mapping);
if (index != (index & 0xffff)) {
throw new InternalCompilerError("MethodHandle-index overflow.");
}
- super.write(dest, mapping);
+ writeFirst(AA, dest);
+ write16BitReference(rewritten, dest, mapping);
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- getMethodHandle().collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexMethodHandle rewritten =
+ rewriter.rewriteDexMethodHandle(
+ getMethodHandle(), MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, context);
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstMethodType.java b/src/main/java/com/android/tools/r8/code/ConstMethodType.java
index 8eb5443..4767025 100644
--- a/src/main/java/com/android/tools/r8/code/ConstMethodType.java
+++ b/src/main/java/com/android/tools/r8/code/ConstMethodType.java
@@ -6,10 +6,13 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.OffsetToObjectMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -62,17 +65,29 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
- int index = BBBB.getOffset(mapping);
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ DexProto rewritten = rewriter.rewriteProto(getMethodType());
+ int index = rewritten.getOffset(mapping);
if (index != (index & 0xffff)) {
throw new InternalCompilerError("MethodType-index overflow.");
}
- super.write(dest, mapping);
+ writeFirst(AA, dest);
+ write16BitReference(rewritten, dest, mapping);
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- getMethodType().collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexProto rewritten = rewriter.rewriteProto(getMethodType());
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/ConstString.java b/src/main/java/com/android/tools/r8/code/ConstString.java
index 261016b..8bccec9 100644
--- a/src/main/java/com/android/tools/r8/code/ConstString.java
+++ b/src/main/java/com/android/tools/r8/code/ConstString.java
@@ -6,9 +6,12 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.InternalCompilerError;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.OffsetToObjectMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -31,7 +34,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
getString().collectIndexedItems(indexedItems);
}
@@ -71,12 +78,17 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
int index = BBBB.getOffset(mapping);
if (index != (index & 0xffff)) {
throw new InternalCompilerError("String-index overflow.");
}
- super.write(dest, mapping);
+ super.write(dest, context, graphLens, mapping, rewriter);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/DexInitClass.java b/src/main/java/com/android/tools/r8/code/DexInitClass.java
index 20f2047..52cd9e1 100644
--- a/src/main/java/com/android/tools/r8/code/DexInitClass.java
+++ b/src/main/java/com/android/tools/r8/code/DexInitClass.java
@@ -8,10 +8,13 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.code.FieldMemberType;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -36,9 +39,16 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- DexField field = indexedItems.getInitClassLens().getInitClassField(clazz);
- field.collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ // We intentionally apply the graph lens first, and then the init class lens, using the fact
+ // that the init class lens maps classes in the final program to fields in the final program.
+ DexType rewrittenClass = graphLens.lookupType(clazz);
+ DexField clinitField = indexedItems.getInitClassLens().getInitClassField(rewrittenClass);
+ clinitField.collectIndexedItems(indexedItems);
}
@Override
@@ -91,10 +101,18 @@
}
@Override
- public void write(ShortBuffer buffer, ObjectToOffsetMapping mapping) {
- DexField field = mapping.getClinitField(clazz);
- writeFirst(dest, buffer, getOpcode(field));
- write16BitReference(field, buffer, mapping);
+ public void write(
+ ShortBuffer buffer,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ // We intentionally apply the graph lens first, and then the init class lens, using the fact
+ // that the init class lens maps classes in the final program to fields in the final program.
+ DexType rewrittenClass = graphLens.lookupType(clazz);
+ DexField clinitField = mapping.getClinitField(rewrittenClass);
+ writeFirst(dest, buffer, getOpcode(clinitField));
+ write16BitReference(clinitField, buffer, mapping);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java b/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java
index 1fb6e8c..c50bba8 100644
--- a/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java
+++ b/src/main/java/com/android/tools/r8/code/DexItemBasedConstString.java
@@ -6,9 +6,12 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.DexReference;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.dexitembasedstring.NameComputationInfo;
import java.nio.ShortBuffer;
@@ -35,7 +38,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
getItem().collectIndexedItems(indexedItems);
}
@@ -78,7 +85,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
throw new Unreachable(
"DexItemBasedConstString instructions should always be rewritten into ConstString");
}
diff --git a/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java b/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java
index 36338f9..20d412f 100644
--- a/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java
+++ b/src/main/java/com/android/tools/r8/code/FillArrayDataPayload.java
@@ -3,8 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
import java.nio.ShortBuffer;
@@ -42,12 +45,17 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(3, dest); // Pseudo-opcode = 0x0300
write16BitValue(element_width, dest);
write32BitValue(size, dest);
- for (int i = 0; i < data.length; i++) {
- write16BitValue(data[i], dest);
+ for (short datum : data) {
+ write16BitValue(datum, dest);
}
}
diff --git a/src/main/java/com/android/tools/r8/code/FilledNewArray.java b/src/main/java/com/android/tools/r8/code/FilledNewArray.java
index 1932e16..5198876 100644
--- a/src/main/java/com/android/tools/r8/code/FilledNewArray.java
+++ b/src/main/java/com/android/tools/r8/code/FilledNewArray.java
@@ -5,8 +5,13 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.OffsetToObjectMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import java.nio.ShortBuffer;
public class FilledNewArray extends Format35c<DexType> {
@@ -38,8 +43,13 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- getType().collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexType rewritten = graphLens.lookupType(getType());
+ rewritten.collectIndexedItems(indexedItems);
}
public DexType getType() {
@@ -55,4 +65,17 @@
public boolean canThrow() {
return true;
}
+
+ @Override
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ DexType rewritten = graphLens.lookupType(getType());
+ writeFirst(A, G, dest);
+ write16BitReference(rewritten, dest, mapping);
+ write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java b/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
index 7fc2adc..de651f5 100644
--- a/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
+++ b/src/main/java/com/android/tools/r8/code/FilledNewArrayRange.java
@@ -5,8 +5,13 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.OffsetToObjectMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import java.nio.ShortBuffer;
public class FilledNewArrayRange extends Format3rc<DexType> {
@@ -38,8 +43,13 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- getType().collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexType rewritten = graphLens.lookupType(getType());
+ rewritten.collectIndexedItems(indexedItems);
}
public DexType getType() {
@@ -55,4 +65,17 @@
public boolean canThrow() {
return true;
}
+
+ @Override
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ DexType rewritten = graphLens.lookupType(getType());
+ writeFirst(AA, dest);
+ write16BitReference(rewritten, dest, mapping);
+ write16BitValue(CCCC, dest);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/Format10t.java b/src/main/java/com/android/tools/r8/code/Format10t.java
index 4c61fa3..d34ecb2 100644
--- a/src/main/java/com/android/tools/r8/code/Format10t.java
+++ b/src/main/java/com/android/tools/r8/code/Format10t.java
@@ -4,7 +4,10 @@
package com.android.tools.r8.code;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -25,7 +28,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
}
@@ -53,7 +61,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format10x.java b/src/main/java/com/android/tools/r8/code/Format10x.java
index 8eed571..6ffc866 100644
--- a/src/main/java/com/android/tools/r8/code/Format10x.java
+++ b/src/main/java/com/android/tools/r8/code/Format10x.java
@@ -4,7 +4,10 @@
package com.android.tools.r8.code;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -20,7 +23,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(0, dest);
}
@@ -45,7 +53,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format11n.java b/src/main/java/com/android/tools/r8/code/Format11n.java
index f2b8ac2..933beba 100644
--- a/src/main/java/com/android/tools/r8/code/Format11n.java
+++ b/src/main/java/com/android/tools/r8/code/Format11n.java
@@ -5,7 +5,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -34,7 +37,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(B, A, dest);
}
@@ -58,7 +66,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format11x.java b/src/main/java/com/android/tools/r8/code/Format11x.java
index 318bf04..5d627bd 100644
--- a/src/main/java/com/android/tools/r8/code/Format11x.java
+++ b/src/main/java/com/android/tools/r8/code/Format11x.java
@@ -5,7 +5,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -25,7 +28,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
}
@@ -53,7 +61,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format12x.java b/src/main/java/com/android/tools/r8/code/Format12x.java
index ac90623..36284b9 100644
--- a/src/main/java/com/android/tools/r8/code/Format12x.java
+++ b/src/main/java/com/android/tools/r8/code/Format12x.java
@@ -5,7 +5,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -28,7 +31,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(B, A, dest);
}
@@ -57,7 +65,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format20t.java b/src/main/java/com/android/tools/r8/code/Format20t.java
index f145476..42d172a 100644
--- a/src/main/java/com/android/tools/r8/code/Format20t.java
+++ b/src/main/java/com/android/tools/r8/code/Format20t.java
@@ -4,7 +4,10 @@
package com.android.tools.r8.code;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -24,7 +27,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(0, dest);
write16BitValue(AAAA, dest);
}
@@ -53,7 +61,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format21c.java b/src/main/java/com/android/tools/r8/code/Format21c.java
index 04848f0..9118072 100644
--- a/src/main/java/com/android/tools/r8/code/Format21c.java
+++ b/src/main/java/com/android/tools/r8/code/Format21c.java
@@ -4,8 +4,11 @@
package com.android.tools.r8.code;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
import java.util.function.BiPredicate;
@@ -29,7 +32,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
write16BitReference(BBBB, dest, mapping);
}
diff --git a/src/main/java/com/android/tools/r8/code/Format21h.java b/src/main/java/com/android/tools/r8/code/Format21h.java
index 221dc9e..848990d 100644
--- a/src/main/java/com/android/tools/r8/code/Format21h.java
+++ b/src/main/java/com/android/tools/r8/code/Format21h.java
@@ -5,7 +5,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import java.nio.ShortBuffer;
abstract class Format21h extends Base2Format {
@@ -28,7 +31,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
write16BitValue(BBBB, dest);
}
@@ -48,7 +56,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format21s.java b/src/main/java/com/android/tools/r8/code/Format21s.java
index a9d7dc1..31c4bc9 100644
--- a/src/main/java/com/android/tools/r8/code/Format21s.java
+++ b/src/main/java/com/android/tools/r8/code/Format21s.java
@@ -5,7 +5,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
import java.nio.ShortBuffer;
@@ -30,7 +33,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
write16BitValue(BBBB, dest);
}
@@ -60,7 +68,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format21t.java b/src/main/java/com/android/tools/r8/code/Format21t.java
index d89b029..5e52bac 100644
--- a/src/main/java/com/android/tools/r8/code/Format21t.java
+++ b/src/main/java/com/android/tools/r8/code/Format21t.java
@@ -5,10 +5,13 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.If.Type;
import com.android.tools.r8.ir.code.ValueTypeConstraint;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -32,7 +35,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
write16BitValue(BBBB, dest);
}
@@ -78,7 +86,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format22b.java b/src/main/java/com/android/tools/r8/code/Format22b.java
index 3952eb7..48955dc 100644
--- a/src/main/java/com/android/tools/r8/code/Format22b.java
+++ b/src/main/java/com/android/tools/r8/code/Format22b.java
@@ -5,7 +5,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
import java.nio.ShortBuffer;
@@ -34,7 +37,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
write16BitValue(combineBytes(CC, BB), dest);
}
@@ -65,7 +73,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format22c.java b/src/main/java/com/android/tools/r8/code/Format22c.java
index 751ef61..0ff7841 100644
--- a/src/main/java/com/android/tools/r8/code/Format22c.java
+++ b/src/main/java/com/android/tools/r8/code/Format22c.java
@@ -4,13 +4,12 @@
package com.android.tools.r8.code;
import com.android.tools.r8.dex.Constants;
+import com.android.tools.r8.graph.DexReference;
import com.android.tools.r8.graph.IndexedDexItem;
-import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.naming.ClassNameMapper;
-import java.nio.ShortBuffer;
import java.util.function.BiPredicate;
-public abstract class Format22c<T extends IndexedDexItem> extends Base2Format {
+public abstract class Format22c<T extends DexReference> extends Base2Format {
public final byte A;
public final byte B;
@@ -33,12 +32,6 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
- writeFirst(B, A, dest);
- write16BitReference(CCCC, dest, mapping);
- }
-
- @Override
public final int hashCode() {
return ((CCCC.hashCode() << 8) | (A << 4) | B) ^ getClass().hashCode();
}
diff --git a/src/main/java/com/android/tools/r8/code/Format22s.java b/src/main/java/com/android/tools/r8/code/Format22s.java
index 25c51d6..1b9aeb4 100644
--- a/src/main/java/com/android/tools/r8/code/Format22s.java
+++ b/src/main/java/com/android/tools/r8/code/Format22s.java
@@ -5,7 +5,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
import java.nio.ShortBuffer;
@@ -34,7 +37,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(B, A, dest);
write16BitValue(CCCC, dest);
}
@@ -65,7 +73,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format22t.java b/src/main/java/com/android/tools/r8/code/Format22t.java
index 6505e5c..4e75d23 100644
--- a/src/main/java/com/android/tools/r8/code/Format22t.java
+++ b/src/main/java/com/android/tools/r8/code/Format22t.java
@@ -5,10 +5,13 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.ir.code.If.Type;
import com.android.tools.r8.ir.code.ValueTypeConstraint;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -36,7 +39,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(B, A, dest);
write16BitValue(CCCC, dest);
}
@@ -82,7 +90,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format22x.java b/src/main/java/com/android/tools/r8/code/Format22x.java
index 5c1b2c4..901af1e 100644
--- a/src/main/java/com/android/tools/r8/code/Format22x.java
+++ b/src/main/java/com/android/tools/r8/code/Format22x.java
@@ -5,7 +5,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -29,7 +32,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
write16BitValue(BBBB, dest);
}
@@ -59,7 +67,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format23x.java b/src/main/java/com/android/tools/r8/code/Format23x.java
index 739b66f..e9d030b 100644
--- a/src/main/java/com/android/tools/r8/code/Format23x.java
+++ b/src/main/java/com/android/tools/r8/code/Format23x.java
@@ -5,7 +5,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -33,7 +36,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
write16BitValue(combineBytes(CC, BB), dest);
}
@@ -63,7 +71,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format30t.java b/src/main/java/com/android/tools/r8/code/Format30t.java
index bfcf0d3..dcf5064 100644
--- a/src/main/java/com/android/tools/r8/code/Format30t.java
+++ b/src/main/java/com/android/tools/r8/code/Format30t.java
@@ -4,7 +4,10 @@
package com.android.tools.r8.code;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -23,7 +26,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(0, dest);
write32BitValue(AAAAAAAA, dest);
}
@@ -52,7 +60,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format31c.java b/src/main/java/com/android/tools/r8/code/Format31c.java
index ead4920..023aeac 100644
--- a/src/main/java/com/android/tools/r8/code/Format31c.java
+++ b/src/main/java/com/android/tools/r8/code/Format31c.java
@@ -7,8 +7,11 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
import java.util.function.BiPredicate;
@@ -32,7 +35,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
write32BitReference(BBBBBBBB, dest, mapping);
}
@@ -58,7 +66,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
BBBBBBBB.collectIndexedItems(indexedItems);
}
diff --git a/src/main/java/com/android/tools/r8/code/Format31i.java b/src/main/java/com/android/tools/r8/code/Format31i.java
index 5e55ca4..843319b 100644
--- a/src/main/java/com/android/tools/r8/code/Format31i.java
+++ b/src/main/java/com/android/tools/r8/code/Format31i.java
@@ -5,7 +5,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -28,7 +31,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
write32BitValue(BBBBBBBB, dest);
}
@@ -53,7 +61,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format31t.java b/src/main/java/com/android/tools/r8/code/Format31t.java
index d650fed..9c7fdfd 100644
--- a/src/main/java/com/android/tools/r8/code/Format31t.java
+++ b/src/main/java/com/android/tools/r8/code/Format31t.java
@@ -5,7 +5,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -28,7 +31,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
assert (getOffset() + BBBBBBBB) % 2 == 0;
write32BitValue(BBBBBBBB, dest);
@@ -68,7 +76,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format32x.java b/src/main/java/com/android/tools/r8/code/Format32x.java
index a31a494..34ecf4f 100644
--- a/src/main/java/com/android/tools/r8/code/Format32x.java
+++ b/src/main/java/com/android/tools/r8/code/Format32x.java
@@ -6,7 +6,10 @@
import static com.android.tools.r8.dex.Constants.U16BIT_MAX;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -30,7 +33,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(0, dest);
write16BitValue(AAAA, dest);
write16BitValue(BBBB, dest);
@@ -61,7 +69,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/Format35c.java b/src/main/java/com/android/tools/r8/code/Format35c.java
index fba7d0d..8c2cb22 100644
--- a/src/main/java/com/android/tools/r8/code/Format35c.java
+++ b/src/main/java/com/android/tools/r8/code/Format35c.java
@@ -5,9 +5,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.IndexedDexItem;
-import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.naming.ClassNameMapper;
-import java.nio.ShortBuffer;
import java.util.function.BiPredicate;
public abstract class Format35c<T extends IndexedDexItem> extends Base3Format {
@@ -51,13 +49,6 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
- writeFirst(A, G, dest);
- write16BitReference(BBBB, dest, mapping);
- write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest);
- }
-
- @Override
public final int hashCode() {
return ((BBBB.hashCode() << 24) | (A << 20) | (C << 16) | (D << 12) | (E << 8) | (F << 4)
| G) ^ getClass().hashCode();
diff --git a/src/main/java/com/android/tools/r8/code/Format3rc.java b/src/main/java/com/android/tools/r8/code/Format3rc.java
index a50a9d9..98e78cc 100644
--- a/src/main/java/com/android/tools/r8/code/Format3rc.java
+++ b/src/main/java/com/android/tools/r8/code/Format3rc.java
@@ -5,9 +5,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.graph.IndexedDexItem;
-import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.naming.ClassNameMapper;
-import java.nio.ShortBuffer;
import java.util.function.BiPredicate;
public abstract class Format3rc<T extends IndexedDexItem> extends Base3Format {
@@ -37,13 +35,6 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
- writeFirst(AA, dest);
- write16BitReference(BBBB, dest, mapping);
- write16BitValue(CCCC, dest);
- }
-
- @Override
public final int hashCode() {
return ((CCCC << 24) | (BBBB.hashCode() << 4) | AA) ^ getClass().hashCode();
}
diff --git a/src/main/java/com/android/tools/r8/code/Format45cc.java b/src/main/java/com/android/tools/r8/code/Format45cc.java
index f5123cf..f6820c8 100644
--- a/src/main/java/com/android/tools/r8/code/Format45cc.java
+++ b/src/main/java/com/android/tools/r8/code/Format45cc.java
@@ -8,8 +8,13 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.Invoke.Type;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -87,17 +92,36 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- BBBB.collectIndexedItems(indexedItems);
- HHHH.collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ GraphLensLookupResult lookup =
+ graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC);
+ assert lookup.getType() == Type.POLYMORPHIC;
+ lookup.getMethod().collectIndexedItems(indexedItems);
+
+ DexProto rewrittenProto = rewriter.rewriteProto(getProto());
+ rewrittenProto.collectIndexedItems(indexedItems);
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ GraphLensLookupResult lookup =
+ graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC);
+ assert lookup.getType() == Type.POLYMORPHIC;
writeFirst(A, G, dest);
- write16BitReference(BBBB, dest, mapping);
+ write16BitReference(lookup.getMethod(), dest, mapping);
write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest);
- write16BitReference(HHHH, dest, mapping);
+
+ DexProto rewrittenProto = rewriter.rewriteProto(getProto());
+ write16BitReference(rewrittenProto, dest, mapping);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format4rcc.java b/src/main/java/com/android/tools/r8/code/Format4rcc.java
index 0ec2780..64bbc1e 100644
--- a/src/main/java/com/android/tools/r8/code/Format4rcc.java
+++ b/src/main/java/com/android/tools/r8/code/Format4rcc.java
@@ -7,8 +7,13 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.Invoke.Type;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
import java.util.function.BiPredicate;
@@ -40,11 +45,21 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ GraphLensLookupResult lookup =
+ graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC);
+ assert lookup.getType() == Type.POLYMORPHIC;
writeFirst(AA, dest);
- write16BitReference(BBBB, dest, mapping);
+ write16BitReference(lookup.getMethod(), dest, mapping);
write16BitValue(CCCC, dest);
- write16BitReference(HHHH, dest, mapping);
+
+ DexProto rewrittenProto = rewriter.rewriteProto(getProto());
+ write16BitReference(rewrittenProto, dest, mapping);
}
@Override
@@ -93,9 +108,18 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- BBBB.collectIndexedItems(indexedItems);
- HHHH.collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ GraphLensLookupResult lookup =
+ graphLens.lookupMethod(getMethod(), context.getReference(), Type.POLYMORPHIC);
+ assert lookup.getType() == Type.POLYMORPHIC;
+ lookup.getMethod().collectIndexedItems(indexedItems);
+
+ DexProto rewrittenProto = rewriter.rewriteProto(getProto());
+ rewrittenProto.collectIndexedItems(indexedItems);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/Format51l.java b/src/main/java/com/android/tools/r8/code/Format51l.java
index 0e9ad93..face456 100644
--- a/src/main/java/com/android/tools/r8/code/Format51l.java
+++ b/src/main/java/com/android/tools/r8/code/Format51l.java
@@ -5,7 +5,10 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.dex.IndexedItemCollection;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import java.nio.ShortBuffer;
@@ -28,7 +31,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(AA, dest);
write64BitValue(BBBBBBBBBBBBBBBB, dest);
}
@@ -53,7 +61,11 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
// No references.
}
}
diff --git a/src/main/java/com/android/tools/r8/code/IgetOrIput.java b/src/main/java/com/android/tools/r8/code/IgetOrIput.java
index 7800ace..33621e5 100644
--- a/src/main/java/com/android/tools/r8/code/IgetOrIput.java
+++ b/src/main/java/com/android/tools/r8/code/IgetOrIput.java
@@ -5,6 +5,11 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import java.nio.ShortBuffer;
public abstract class IgetOrIput extends Format22c<DexField> {
@@ -17,12 +22,29 @@
}
@Override
- public final void collectIndexedItems(IndexedItemCollection indexedItems) {
- getField().collectIndexedItems(indexedItems);
+ public final void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexField rewritten = graphLens.lookupField(getField());
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
public final DexField getField() {
return CCCC;
}
+
+ @Override
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ DexField lookup = graphLens.lookupField(getField());
+ writeFirst(B, A, dest);
+ write16BitReference(lookup, dest, mapping);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/InstanceOf.java b/src/main/java/com/android/tools/r8/code/InstanceOf.java
index 05a9558..6c9d960 100644
--- a/src/main/java/com/android/tools/r8/code/InstanceOf.java
+++ b/src/main/java/com/android/tools/r8/code/InstanceOf.java
@@ -5,9 +5,14 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.OffsetToObjectMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import java.nio.ShortBuffer;
public class InstanceOf extends Format22c<DexType> {
@@ -49,8 +54,13 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- getType().collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexType rewritten = graphLens.lookupType(getType());
+ rewritten.collectIndexedItems(indexedItems);
}
public DexType getType() {
@@ -71,4 +81,16 @@
public boolean canThrow() {
return true;
}
+
+ @Override
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ DexType lookup = graphLens.lookupType(getType());
+ writeFirst(B, A, dest);
+ write16BitReference(lookup, dest, mapping);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/Instruction.java b/src/main/java/com/android/tools/r8/code/Instruction.java
index d8accd7..766638c 100644
--- a/src/main/java/com/android/tools/r8/code/Instruction.java
+++ b/src/main/java/com/android/tools/r8/code/Instruction.java
@@ -9,10 +9,13 @@
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.IndexedDexItem;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
import java.nio.ShortBuffer;
@@ -90,7 +93,11 @@
}
protected void writeFirst(int a, int b, ShortBuffer dest) {
- dest.put((short) (((a & 0xf) << 12) | ((b & 0xf) << 8) | (getOpcode() & 0xff)));
+ writeFirst(a, b, dest, getOpcode());
+ }
+
+ protected void writeFirst(int a, int b, ShortBuffer dest, int opcode) {
+ dest.put((short) (((a & 0xf) << 12) | ((b & 0xf) << 8) | (opcode & 0xff)));
}
protected void write16BitValue(int value, ShortBuffer dest) {
@@ -107,8 +114,8 @@
write32BitValue((value >> 32) & 0xffffffff, dest);
}
- protected void write16BitReference(IndexedDexItem item, ShortBuffer dest,
- ObjectToOffsetMapping mapping) {
+ protected void write16BitReference(
+ IndexedDexItem item, ShortBuffer dest, ObjectToOffsetMapping mapping) {
int index = item.getOffset(mapping);
assert index == (index & 0xffff);
write16BitValue(index, dest);
@@ -309,9 +316,18 @@
return toString(null);
}
- public abstract void write(ShortBuffer buffer, ObjectToOffsetMapping mapping);
+ public abstract void write(
+ ShortBuffer buffer,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter);
- public abstract void collectIndexedItems(IndexedItemCollection indexedItems);
+ public abstract void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter);
public boolean equals(Instruction other, BiPredicate<IndexedDexItem, IndexedDexItem> equality) {
// In the default case, there is nothing to substitute.
diff --git a/src/main/java/com/android/tools/r8/code/InvokeCustom.java b/src/main/java/com/android/tools/r8/code/InvokeCustom.java
index 72d0adb..1355f13 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeCustom.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeCustom.java
@@ -5,9 +5,14 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.OffsetToObjectMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import java.nio.ShortBuffer;
public class InvokeCustom extends Format35c<DexCallSite> {
@@ -39,8 +44,13 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- getCallSite().collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexCallSite rewritten = rewriter.rewriteCallSite(getCallSite(), context);
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
@@ -62,4 +72,16 @@
public boolean canThrow() {
return true;
}
+
+ @Override
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ writeFirst(A, G, dest);
+ write16BitReference(rewriter.rewriteCallSite(getCallSite(), context), dest, mapping);
+ write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java b/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java
index ae63c4d..2d09e4f 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeCustomRange.java
@@ -5,9 +5,14 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.OffsetToObjectMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import java.nio.ShortBuffer;
public class InvokeCustomRange extends Format3rc<DexCallSite> {
@@ -39,8 +44,13 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- getCallSite().collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexCallSite rewritten = rewriter.rewriteCallSite(getCallSite(), context);
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
@@ -62,4 +72,17 @@
public boolean canThrow() {
return true;
}
+
+ @Override
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ DexCallSite rewritten = rewriter.rewriteCallSite(getCallSite(), context);
+ writeFirst(AA, dest);
+ write16BitReference(rewritten, dest, mapping);
+ write16BitValue(CCCC, dest);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeDirect.java b/src/main/java/com/android/tools/r8/code/InvokeDirect.java
index cd8c1b7..6786de8 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeDirect.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeDirect.java
@@ -24,6 +24,11 @@
}
@Override
+ public Type getInvokeType() {
+ return Type.DIRECT;
+ }
+
+ @Override
public String getName() {
return NAME;
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java b/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java
index 41070dd..843d968 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeDirectRange.java
@@ -24,6 +24,11 @@
}
@Override
+ public Type getInvokeType() {
+ return Type.DIRECT;
+ }
+
+ @Override
public String getName() {
return NAME;
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeInterface.java b/src/main/java/com/android/tools/r8/code/InvokeInterface.java
index 3e172e2..89b8a16 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeInterface.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeInterface.java
@@ -24,6 +24,11 @@
}
@Override
+ public Type getInvokeType() {
+ return Type.INTERFACE;
+ }
+
+ @Override
public String getName() {
return NAME;
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java b/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java
index 2d1986c..e710b8c 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeInterfaceRange.java
@@ -24,6 +24,11 @@
}
@Override
+ public Type getInvokeType() {
+ return Type.INTERFACE;
+ }
+
+ @Override
public String getName() {
return NAME;
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeMethod.java b/src/main/java/com/android/tools/r8/code/InvokeMethod.java
index cab1eac..c8539f3 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeMethod.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeMethod.java
@@ -5,6 +5,13 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult;
+import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.Invoke;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import java.nio.ShortBuffer;
public abstract class InvokeMethod extends Format35c<DexMethod> {
@@ -17,12 +24,34 @@
}
@Override
- public final void collectIndexedItems(IndexedItemCollection indexedItems) {
- getMethod().collectIndexedItems(indexedItems);
+ public final void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexMethod rewritten =
+ graphLens.lookupMethod(getMethod(), context.getReference(), getInvokeType()).getMethod();
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
public final DexMethod getMethod() {
return BBBB;
}
+
+ public abstract Invoke.Type getInvokeType();
+
+ @Override
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ GraphLensLookupResult lookup =
+ graphLens.lookupMethod(getMethod(), context.getReference(), getInvokeType());
+ writeFirst(A, G, dest, lookup.getType().getDexOpcode());
+ write16BitReference(lookup.getMethod(), dest, mapping);
+ write16BitValue(combineBytes(makeByte(F, E), makeByte(D, C)), dest);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java b/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java
index 25fad42..4e4d705 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeMethodRange.java
@@ -5,6 +5,13 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult;
+import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.code.Invoke.Type;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import java.nio.ShortBuffer;
public abstract class InvokeMethodRange extends Format3rc<DexMethod> {
@@ -17,12 +24,34 @@
}
@Override
- public final void collectIndexedItems(IndexedItemCollection indexedItems) {
- getMethod().collectIndexedItems(indexedItems);
+ public final void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexMethod rewritten =
+ graphLens.lookupMethod(getMethod(), context.getReference(), getInvokeType()).getMethod();
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
public final DexMethod getMethod() {
return BBBB;
}
+
+ public abstract Type getInvokeType();
+
+ @Override
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ GraphLensLookupResult lookup =
+ graphLens.lookupMethod(getMethod(), context.getReference(), getInvokeType());
+ writeFirst(AA, dest, lookup.getType().getDexOpcodeRange());
+ write16BitReference(lookup.getMethod(), dest, mapping);
+ write16BitValue(CCCC, dest);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeStatic.java b/src/main/java/com/android/tools/r8/code/InvokeStatic.java
index 531105b..796b183 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeStatic.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeStatic.java
@@ -24,6 +24,11 @@
}
@Override
+ public Type getInvokeType() {
+ return Type.STATIC;
+ }
+
+ @Override
public String getName() {
return NAME;
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java b/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java
index 7d3ff3d..20809c9 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeStaticRange.java
@@ -24,6 +24,11 @@
}
@Override
+ public Type getInvokeType() {
+ return Type.STATIC;
+ }
+
+ @Override
public String getName() {
return NAME;
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeSuper.java b/src/main/java/com/android/tools/r8/code/InvokeSuper.java
index 1dc8ac6..d2d6e28 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeSuper.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeSuper.java
@@ -24,6 +24,11 @@
}
@Override
+ public Type getInvokeType() {
+ return Type.SUPER;
+ }
+
+ @Override
public String getName() {
return NAME;
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java b/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java
index af6ebe8..70fd726 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeSuperRange.java
@@ -24,6 +24,11 @@
}
@Override
+ public Type getInvokeType() {
+ return Type.SUPER;
+ }
+
+ @Override
public String getName() {
return NAME;
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeVirtual.java b/src/main/java/com/android/tools/r8/code/InvokeVirtual.java
index 17596a4..9b9e064 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeVirtual.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeVirtual.java
@@ -24,6 +24,11 @@
}
@Override
+ public Type getInvokeType() {
+ return Type.VIRTUAL;
+ }
+
+ @Override
public String getName() {
return NAME;
}
diff --git a/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java b/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
index c2a0d6c..a4f2e98 100644
--- a/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
+++ b/src/main/java/com/android/tools/r8/code/InvokeVirtualRange.java
@@ -24,6 +24,11 @@
}
@Override
+ public Type getInvokeType() {
+ return Type.VIRTUAL;
+ }
+
+ @Override
public String getName() {
return NAME;
}
diff --git a/src/main/java/com/android/tools/r8/code/NewArray.java b/src/main/java/com/android/tools/r8/code/NewArray.java
index dfb4ccb..a0104a2 100644
--- a/src/main/java/com/android/tools/r8/code/NewArray.java
+++ b/src/main/java/com/android/tools/r8/code/NewArray.java
@@ -5,9 +5,14 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.OffsetToObjectMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
+import java.nio.ShortBuffer;
public class NewArray extends Format22c<DexType> {
@@ -39,8 +44,13 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- getType().collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexType rewritten = graphLens.lookupType(getType());
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
@@ -61,4 +71,16 @@
public boolean canThrow() {
return true;
}
+
+ @Override
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
+ DexType lookup = graphLens.lookupType(getType());
+ writeFirst(B, A, dest);
+ write16BitReference(lookup, dest, mapping);
+ }
}
diff --git a/src/main/java/com/android/tools/r8/code/NewInstance.java b/src/main/java/com/android/tools/r8/code/NewInstance.java
index 695ae96..da58744 100644
--- a/src/main/java/com/android/tools/r8/code/NewInstance.java
+++ b/src/main/java/com/android/tools/r8/code/NewInstance.java
@@ -5,9 +5,12 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.OffsetToObjectMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.graph.UseRegistry;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
public class NewInstance extends Format21c<DexType> {
@@ -39,8 +42,13 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- getType().collectIndexedItems(indexedItems);
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexType rewritten = graphLens.lookupType(getType());
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java b/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java
index 110f668..c7caf43 100644
--- a/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/code/PackedSwitchPayload.java
@@ -3,7 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
import java.nio.ShortBuffer;
@@ -38,7 +41,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(1, dest); // Pseudo-opcode = 0x0100
write16BitValue(size, dest);
write32BitValue(first_key, dest);
diff --git a/src/main/java/com/android/tools/r8/code/SgetOrSput.java b/src/main/java/com/android/tools/r8/code/SgetOrSput.java
index d04e098..1f77122 100644
--- a/src/main/java/com/android/tools/r8/code/SgetOrSput.java
+++ b/src/main/java/com/android/tools/r8/code/SgetOrSput.java
@@ -5,6 +5,9 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
abstract class SgetOrSput extends Format21c<DexField> {
@@ -17,8 +20,13 @@
}
@Override
- public final void collectIndexedItems(IndexedItemCollection indexedItems) {
- getField().collectIndexedItems(indexedItems);
+ public final void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
+ DexField rewritten = graphLens.lookupField(getField());
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java b/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java
index 90b88cc..b73779b 100644
--- a/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java
+++ b/src/main/java/com/android/tools/r8/code/SparseSwitchPayload.java
@@ -3,7 +3,10 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.code;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.utils.StringUtils;
import java.nio.ShortBuffer;
@@ -42,7 +45,12 @@
}
@Override
- public void write(ShortBuffer dest, ObjectToOffsetMapping mapping) {
+ public void write(
+ ShortBuffer dest,
+ ProgramMethod context,
+ GraphLens graphLens,
+ ObjectToOffsetMapping mapping,
+ LensCodeRewriterUtils rewriter) {
writeFirst(2, dest); // Pseudo-opcode = 0x0200
write16BitValue(size, dest);
for (int i = 0; i < size; i++) {
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
index 5190adb..6b0d055 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationReader.java
@@ -24,10 +24,12 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexLibraryClass;
import com.android.tools.r8.graph.DexProgramClass;
+import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.JarApplicationReader;
import com.android.tools.r8.graph.JarClassFileReader;
import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.naming.ClassNameMapper;
+import com.android.tools.r8.shaking.MainDexClasses;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.AndroidApp;
import com.android.tools.r8.utils.ClassProvider;
@@ -36,7 +38,7 @@
import com.android.tools.r8.utils.DexVersion;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.LibraryClassCollection;
-import com.android.tools.r8.utils.MainDexList;
+import com.android.tools.r8.utils.MainDexListParser;
import com.android.tools.r8.utils.ProgramClassCollection;
import com.android.tools.r8.utils.StringDiagnostic;
import com.android.tools.r8.utils.ThreadUtils;
@@ -78,7 +80,9 @@
return read((StringResource) null);
}
- public LazyLoadedDexApplication read(StringResource proguardMap) throws IOException {
+ public LazyLoadedDexApplication read(
+ StringResource proguardMap)
+ throws IOException {
ExecutorService executor = Executors.newSingleThreadExecutor();
try {
return read(proguardMap, executor);
@@ -87,7 +91,9 @@
}
}
- public final LazyLoadedDexApplication read(ExecutorService executorService) throws IOException {
+ public final LazyLoadedDexApplication read(
+ ExecutorService executorService)
+ throws IOException {
return read(
inputApp.getProguardMapInputData(),
executorService,
@@ -95,7 +101,9 @@
}
public final LazyLoadedDexApplication read(
- StringResource proguardMap, ExecutorService executorService) throws IOException {
+ StringResource proguardMap,
+ ExecutorService executorService)
+ throws IOException {
return read(
proguardMap,
executorService,
@@ -146,7 +154,6 @@
// about class descriptor.
// TODO: try and preload less classes.
readProguardMap(proguardMap, builder, executorService, futures);
- readMainDexList(builder, executorService, futures);
ClassReader classReader = new ClassReader(executorService, futures);
JarClassFileReader jcf = classReader.readSources();
ThreadUtils.awaitFutures(futures);
@@ -167,6 +174,38 @@
return builder.build();
}
+ public MainDexClasses readMainDexClasses(DexApplication app) {
+ MainDexClasses.Builder builder = MainDexClasses.builder();
+ if (inputApp.hasMainDexList()) {
+ for (StringResource resource : inputApp.getMainDexListResources()) {
+ addToMainDexClasses(app, builder, MainDexListParser.parseList(resource, itemFactory));
+ }
+ addToMainDexClasses(
+ app,
+ builder,
+ inputApp.getMainDexClasses().stream()
+ .map(clazz -> itemFactory.createType(DescriptorUtils.javaTypeToDescriptor(clazz)))
+ .collect(Collectors.toList()));
+ }
+ return builder.build();
+ }
+
+ private void addToMainDexClasses(
+ DexApplication app, MainDexClasses.Builder builder, Iterable<DexType> types) {
+ for (DexType type : types) {
+ DexProgramClass clazz = app.programDefinitionFor(type);
+ if (clazz != null) {
+ builder.add(clazz);
+ } else if (!options.ignoreMainDexMissingClasses) {
+ options.reporter.warning(
+ new StringDiagnostic(
+ "Application does not contain `"
+ + type.toSourceString()
+ + "` as referenced in main-dex-list."));
+ }
+ }
+ }
+
private static void dumpInputToFile(AndroidApp app, Path output, InternalOptions options) {
app.dump(output, options);
}
@@ -220,23 +259,6 @@
}));
}
- private void readMainDexList(DexApplication.Builder<?> builder, ExecutorService executorService,
- List<Future<?>> futures) {
- if (inputApp.hasMainDexList()) {
- futures.add(executorService.submit(() -> {
- for (StringResource resource : inputApp.getMainDexListResources()) {
- builder.addToMainDexList(MainDexList.parseList(resource, itemFactory));
- }
-
- builder.addToMainDexList(
- inputApp.getMainDexClasses()
- .stream()
- .map(clazz -> itemFactory.createType(DescriptorUtils.javaTypeToDescriptor(clazz)))
- .collect(Collectors.toList()));
- }));
- }
- }
-
private final class ClassReader {
private final ExecutorService executorService;
private final List<Future<?>> futures;
diff --git a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
index 21b5cd4..b0f836c 100644
--- a/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/ApplicationWriter.java
@@ -44,6 +44,7 @@
import com.android.tools.r8.naming.ProguardMapSupplier;
import com.android.tools.r8.naming.ProguardMapSupplier.ProguardMapId;
import com.android.tools.r8.origin.Origin;
+import com.android.tools.r8.shaking.MainDexClasses;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.ExceptionUtils;
import com.android.tools.r8.utils.InternalOptions;
@@ -69,7 +70,6 @@
public class ApplicationWriter {
- public final DexApplication application;
public final AppView<?> appView;
public final GraphLens graphLens;
public final InitClassLens initClassLens;
@@ -146,18 +146,14 @@
}
public ApplicationWriter(
- DexApplication application,
AppView<?> appView,
- InternalOptions options,
List<Marker> markers,
GraphLens graphLens,
InitClassLens initClassLens,
NamingLens namingLens,
ProguardMapSupplier proguardMapSupplier) {
this(
- application,
appView,
- options,
markers,
graphLens,
initClassLens,
@@ -167,20 +163,15 @@
}
public ApplicationWriter(
- DexApplication application,
AppView<?> appView,
- InternalOptions options,
List<Marker> markers,
GraphLens graphLens,
InitClassLens initClassLens,
NamingLens namingLens,
ProguardMapSupplier proguardMapSupplier,
DexIndexedConsumer consumer) {
- assert application != null;
- this.application = application;
this.appView = appView;
- assert options != null;
- this.options = options;
+ this.options = appView.options();
this.desugaredLibraryCodeToKeep = CodeToKeep.createCodeToKeep(options, namingLens);
this.markers = markers;
this.graphLens = graphLens;
@@ -199,7 +190,7 @@
options.getDexFilePerClassFileConsumer().combineSyntheticClassesWithPrimaryClass());
} else if (!options.canUseMultidex()
&& options.mainDexKeepRules.isEmpty()
- && application.mainDexList.isEmpty()
+ && appView.appInfo().getMainDexClasses().isEmpty()
&& options.enableMainDexListCheck) {
distributor = new VirtualFile.MonoDexDistributor(this, options);
} else {
@@ -215,7 +206,7 @@
* This needs to be done after distribute but before dex string sorting.
*/
private void encodeChecksums(Iterable<VirtualFile> files) {
- List<DexProgramClass> classes = application.classes();
+ Collection<DexProgramClass> classes = appView.appInfo().classes();
Reference2LongMap<DexString> inputChecksums = new Reference2LongOpenHashMap<>(classes.size());
for (DexProgramClass clazz : classes) {
inputChecksums.put(clazz.getType().descriptor, clazz.getChecksum());
@@ -226,12 +217,12 @@
DexString desc = clazz.type.descriptor;
toWrite.addChecksum(desc.toString(), inputChecksums.getLong(desc));
}
- file.injectString(application.dexItemFactory.createString(toWrite.toJsonString()));
+ file.injectString(appView.dexItemFactory().createString(toWrite.toJsonString()));
}
}
public void write(ExecutorService executorService) throws IOException, ExecutionException {
- application.timing.begin("DexApplication.write");
+ appView.appInfo().app().timing.begin("DexApplication.write");
ProguardMapId proguardMapId = null;
if (proguardMapSupplier != null && options.proguardMapConsumer != null) {
proguardMapId = proguardMapSupplier.writeProguardMap();
@@ -246,7 +237,7 @@
}
markerStrings = new ArrayList<>(markers.size());
for (Marker marker : markers) {
- markerStrings.add(application.dexItemFactory.createString(marker.toString()));
+ markerStrings.add(appView.dexItemFactory().createString(marker.toString()));
}
}
try {
@@ -266,16 +257,14 @@
}
assert markers == null
|| markers.isEmpty()
- || application.dexItemFactory.extractMarkers() != null;
- assert appView == null
- || appView.withProtoShrinker(
- shrinker ->
- virtualFiles.stream().allMatch(shrinker::verifyDeadProtoTypesNotReferenced),
- true);
+ || appView.dexItemFactory().extractMarkers() != null;
+ assert appView.withProtoShrinker(
+ shrinker -> virtualFiles.stream().allMatch(shrinker::verifyDeadProtoTypesNotReferenced),
+ true);
// TODO(b/151313617): Sorting annotations mutates elements so run single threaded on main.
SortAnnotations sortAnnotations = new SortAnnotations(namingLens);
- application.classes().forEach((clazz) -> clazz.addDependencies(sortAnnotations));
+ appView.appInfo().classes().forEach((clazz) -> clazz.addDependencies(sortAnnotations));
for (VirtualFile virtualFile : virtualFiles) {
if (virtualFile.isEmpty()) {
@@ -305,10 +294,11 @@
}
}
ObjectToOffsetMapping objectMapping =
- virtualFile.computeMapping(application, namingLens, initClassLens);
+ virtualFile.computeMapping(
+ appView.appInfo(), graphLens, namingLens, initClassLens);
MethodToCodeObjectMapping codeMapping =
rewriteCodeWithJumboStrings(
- objectMapping, virtualFile.classes(), application);
+ objectMapping, virtualFile.classes(), appView.appInfo().app());
ByteBufferResult result =
writeDexFile(objectMapping, codeMapping, byteBufferProvider);
ByteDataView data =
@@ -345,9 +335,9 @@
// Fail if there are pending errors, e.g., the program consumers may have reported errors.
options.reporter.failIfPendingErrors();
// Supply info to all additional resource consumers.
- supplyAdditionalConsumers(application, appView, graphLens, namingLens, options);
+ supplyAdditionalConsumers(appView.appInfo().app(), appView, graphLens, namingLens, options);
} finally {
- application.timing.end();
+ appView.appInfo().app().timing.end();
}
}
@@ -365,7 +355,7 @@
}
if (options.mainDexListConsumer != null) {
ExceptionUtils.withConsumeResourceHandler(
- options.reporter, options.mainDexListConsumer, writeMainDexList(application, namingLens));
+ options.reporter, options.mainDexListConsumer, writeMainDexList(appView, namingLens));
ExceptionUtils.withFinishedResourceHandler(options.reporter, options.mainDexListConsumer);
}
@@ -461,7 +451,7 @@
private void insertAttributeAnnotations() {
// Convert inner-class attributes to DEX annotations
- for (DexProgramClass clazz : application.classes()) {
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
EnclosingMethodAttribute enclosingMethod = clazz.getEnclosingMethodAttribute();
List<InnerClassAttribute> innerClasses = clazz.getInnerClasses();
if (enclosingMethod == null && innerClasses.isEmpty()) {
@@ -609,7 +599,7 @@
provider,
objectMapping,
codeMapping,
- application,
+ appView.appInfo().app(),
options,
namingLens,
desugaredLibraryCodeToKeep);
@@ -624,9 +614,11 @@
.replace('.', '/') + ".class";
}
- private static String writeMainDexList(DexApplication application, NamingLens namingLens) {
+ private static String writeMainDexList(AppView<?> appView, NamingLens namingLens) {
+ MainDexClasses mainDexClasses = appView.appInfo().getMainDexClasses();
StringBuilder builder = new StringBuilder();
- List<DexType> list = new ArrayList<>(application.mainDexList);
+ List<DexType> list = new ArrayList<>(mainDexClasses.size());
+ mainDexClasses.forEach(list::add);
list.sort(DexType::slowCompareTo);
list.forEach(
type -> builder.append(mapMainDexListName(type, namingLens)).append('\n'));
diff --git a/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java b/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
index 037d769..b193e73 100644
--- a/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
+++ b/src/main/java/com/android/tools/r8/dex/DexOutputBuffer.java
@@ -6,9 +6,11 @@
import com.android.tools.r8.ByteBufferProvider;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.graph.DexCode;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.utils.EncodedValueUtils;
import com.android.tools.r8.utils.LebUtils;
import com.google.common.annotations.VisibleForTesting;
@@ -93,16 +95,20 @@
}
public void putInstructions(
- Instruction[] insns, ObjectToOffsetMapping mapping, CodeToKeep desugaredLibraryCodeToKeep) {
+ DexCode code,
+ ProgramMethod context,
+ ObjectToOffsetMapping mapping,
+ CodeToKeep desugaredLibraryCodeToKeep) {
int size = 0;
- for (Instruction insn : insns) {
- size += insn.getSize();
+ Instruction[] instructions = code.instructions;
+ for (Instruction instruction : instructions) {
+ size += instruction.getSize();
}
ensureSpaceFor(size * Short.BYTES);
assert byteBuffer.position() % 2 == 0;
ShortBuffer shortBuffer = byteBuffer.asShortBuffer();
- for (int i = 0; i < insns.length; i++) {
- Instruction insn = insns[i];
+ for (int i = 0; i < instructions.length; i++) {
+ Instruction insn = instructions[i];
DexMethod method = insn.getMethod();
DexField field = insn.getField();
if (field != null) {
@@ -117,7 +123,8 @@
} else if (insn.isCheckCast()) {
desugaredLibraryCodeToKeep.recordClass(insn.asCheckCast().getType());
}
- insn.write(shortBuffer, mapping);
+ insn.write(
+ shortBuffer, context, mapping.getGraphLens(), mapping, mapping.getLensCodeRewriter());
}
byteBuffer.position(byteBuffer.position() + shortBuffer.position() * Short.BYTES);
}
diff --git a/src/main/java/com/android/tools/r8/dex/FileWriter.java b/src/main/java/com/android/tools/r8/dex/FileWriter.java
index da90a09..393297a 100644
--- a/src/main/java/com/android/tools/r8/dex/FileWriter.java
+++ b/src/main/java/com/android/tools/r8/dex/FileWriter.java
@@ -46,6 +46,8 @@
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.graph.ProgramClassVisitor;
+import com.android.tools.r8.graph.ProgramDexCode;
+import com.android.tools.r8.graph.ProgramMethod;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.naming.MemberNaming.MethodSignature;
@@ -175,7 +177,7 @@
assert codeMapping.verifyCodeObjects(mixedSectionOffsets.getCodes());
// Sort the codes first, as their order might impact size due to alignment constraints.
- List<DexCode> codes = sortDexCodesByClassName();
+ List<ProgramDexCode> codes = sortDexCodesByClassName();
// Output the debug_info_items first, as they have no dependencies.
dest.moveTo(layout.getCodesOffset() + sizeOfCodeItems(codes));
@@ -185,8 +187,8 @@
// Ensure deterministic ordering of debug info by sorting consistent with the code objects.
layout.setDebugInfosOffset(dest.align(1));
Set<DexDebugInfo> seen = new HashSet<>(mixedSectionOffsets.getDebugInfos().size());
- for (DexCode code : codes) {
- DexDebugInfoForWriting info = code.getDebugInfoForWriting();
+ for (ProgramDexCode code : codes) {
+ DexDebugInfoForWriting info = code.getCode().getDebugInfoForWriting();
if (info != null && seen.add(info)) {
writeDebugItem(info);
}
@@ -323,18 +325,19 @@
return true;
}
- private List<DexCode> sortDexCodesByClassName() {
- Map<DexCode, String> codeToSignatureMap = new IdentityHashMap<>();
- List<DexCode> codesSorted = new ArrayList<>();
+ private List<ProgramDexCode> sortDexCodesByClassName() {
+ Map<ProgramDexCode, String> codeToSignatureMap = new IdentityHashMap<>();
+ List<ProgramDexCode> codesSorted = new ArrayList<>();
for (DexProgramClass clazz : mapping.getClasses()) {
- clazz.forEachMethod(
+ clazz.forEachProgramMethod(
method -> {
- DexCode code = codeMapping.getCode(method);
- assert code != null || method.shouldNotHaveCode();
+ DexCode code = codeMapping.getCode(method.getDefinition());
+ assert code != null || method.getDefinition().shouldNotHaveCode();
if (code != null) {
- codesSorted.add(code);
- addSignaturesFromMethod(
- method, code, codeToSignatureMap, application.getProguardMap());
+ ProgramDexCode programCode = new ProgramDexCode(code, method);
+ codesSorted.add(programCode);
+ codeToSignatureMap.put(
+ programCode, getKeyForDexCodeSorting(method, application.getProguardMap()));
}
});
}
@@ -342,21 +345,17 @@
return codesSorted;
}
- private static void addSignaturesFromMethod(
- DexEncodedMethod method,
- DexCode code,
- Map<DexCode, String> codeToSignatureMap,
- ClassNameMapper proguardMap) {
+ private static String getKeyForDexCodeSorting(ProgramMethod method, ClassNameMapper proguardMap) {
Signature signature;
String originalClassName;
if (proguardMap != null) {
- signature = proguardMap.originalSignatureOf(method.method);
- originalClassName = proguardMap.originalNameOf(method.holder());
+ signature = proguardMap.originalSignatureOf(method.getReference());
+ originalClassName = proguardMap.originalNameOf(method.getHolderType());
} else {
- signature = MethodSignature.fromDexMethod(method.method);
- originalClassName = method.holder().toSourceString();
+ signature = MethodSignature.fromDexMethod(method.getReference());
+ originalClassName = method.getHolderType().toSourceString();
}
- codeToSignatureMap.put(code, originalClassName + signature);
+ return originalClassName + signature;
}
private <T extends IndexedDexItem> void writeFixedSectionItems(
@@ -380,8 +379,8 @@
writeItems(items, offsetSetter, writer, 1);
}
- private <T extends DexItem> void writeItems(Collection<T> items, Consumer<Integer> offsetSetter,
- Consumer<T> writer, int alignment) {
+ private <T> void writeItems(
+ Collection<T> items, Consumer<Integer> offsetSetter, Consumer<T> writer, int alignment) {
if (items.isEmpty()) {
offsetSetter.accept(0);
} else {
@@ -390,11 +389,11 @@
}
}
- private int sizeOfCodeItems(Iterable<DexCode> codes) {
+ private int sizeOfCodeItems(Iterable<ProgramDexCode> codes) {
int size = 0;
- for (DexCode code : codes) {
+ for (ProgramDexCode code : codes) {
size = alignSize(4, size);
- size += sizeOfCodeItem(code);
+ size += sizeOfCodeItem(code.getCode());
}
return size;
}
@@ -488,7 +487,11 @@
dest.putBytes(new DebugBytecodeWriter(debugInfo, mapping).generate());
}
- private void writeCodeItem(DexCode code) {
+ private void writeCodeItem(ProgramDexCode code) {
+ writeCodeItem(code.getCode(), code.getMethod());
+ }
+
+ private void writeCodeItem(DexCode code, ProgramMethod method) {
mixedSectionOffsets.setOffsetFor(code, dest.align(4));
// Fixed size header information.
dest.putShort((short) code.registerSize);
@@ -500,7 +503,7 @@
int insnSizeOffset = dest.position();
dest.forward(4);
// Write instruction stream.
- dest.putInstructions(code.instructions, mapping, desugaredLibraryCodeToKeep);
+ dest.putInstructions(code, method, mapping, desugaredLibraryCodeToKeep);
// Compute size and do the backward/forward dance to write the size at the beginning.
int insnSize = dest.position() - insnSizeOffset - 4;
dest.rewind(insnSize + 4);
diff --git a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
index 709eb9d..3a88e5d 100644
--- a/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
+++ b/src/main/java/com/android/tools/r8/dex/InheritanceClassInDexDistributor.java
@@ -6,7 +6,7 @@
import com.android.tools.r8.dex.VirtualFile.VirtualFileCycler;
import com.android.tools.r8.errors.CompilationError;
-import com.android.tools.r8.graph.DexApplication;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
@@ -71,7 +71,7 @@
public void updateNumbersOfIds() {
// Use a temporary VirtualFile to evaluate the number of ids in the group.
- VirtualFile virtualFile = new VirtualFile(0, graphLens, initClassLens, namingLens);
+ VirtualFile virtualFile = new VirtualFile(0, appView, graphLens, initClassLens, namingLens);
// Note: sort not needed.
for (DexProgramClass clazz : members) {
virtualFile.addClass(clazz);
@@ -158,29 +158,30 @@
}
- private boolean isDependingOnMainDexClass(Set<DexProgramClass> mainDexDependents,
- DexProgramClass dexProgramClass) {
- if (dexProgramClass == null) {
+ private boolean isDependingOnMainDexClass(
+ Set<DexProgramClass> mainDexDependents, DexProgramClass clazz) {
+ if (clazz == null) {
return false;
}
// Think: build on one Map<dexProgramClass, Boolean> and split in a second step.
- if (mainDexIndependents.contains(dexProgramClass)) {
+ if (mainDexIndependents.contains(clazz)) {
return false;
}
- if (mainDexDependents.contains(dexProgramClass)) {
+ if (mainDexDependents.contains(clazz)) {
return true;
}
- if (mainDex.classes().contains(dexProgramClass)) {
+ if (mainDex.classes().contains(clazz)) {
return true;
}
boolean isDependent = false;
- if (isDependingOnMainDexClass(mainDexDependents,
- app.programDefinitionFor(dexProgramClass.superType))) {
+ if (isDependingOnMainDexClass(
+ mainDexDependents, appView.programDefinitionFor(clazz.superType, clazz))) {
isDependent = true;
} else {
- for (DexType interfaze : dexProgramClass.interfaces.values) {
- if (isDependingOnMainDexClass(mainDexDependents, app.programDefinitionFor(interfaze))) {
+ for (DexType interfaze : clazz.interfaces.values) {
+ if (isDependingOnMainDexClass(
+ mainDexDependents, appView.programDefinitionFor(interfaze, clazz))) {
isDependent = true;
break;
}
@@ -188,38 +189,37 @@
}
if (isDependent) {
- mainDexDependents.add(dexProgramClass);
+ mainDexDependents.add(clazz);
} else {
- mainDexIndependents.add(dexProgramClass);
+ mainDexIndependents.add(clazz);
}
return isDependent;
}
-
- private boolean isDependingOnMainDexIndependents(DexProgramClass dexProgramClass) {
- if (dexProgramClass == null) {
+ private boolean isDependingOnMainDexIndependents(DexProgramClass clazz) {
+ if (clazz == null) {
return false;
}
// Think: build on one Map<dexProgramClass, Boolean> and split in a second step.
- if (independentsFromMainDexIndependents.contains(dexProgramClass)) {
+ if (independentsFromMainDexIndependents.contains(clazz)) {
return false;
}
- if (dependentsOfMainDexIndependents.contains(dexProgramClass)) {
+ if (dependentsOfMainDexIndependents.contains(clazz)) {
return true;
}
- if (mainDex.classes().contains(dexProgramClass)) {
+ if (mainDex.classes().contains(clazz)) {
return false;
}
- if (mainDexIndependents.contains(dexProgramClass)) {
+ if (mainDexIndependents.contains(clazz)) {
return true;
}
boolean isDependent = false;
- if (isDependingOnMainDexIndependents(app.programDefinitionFor(dexProgramClass.superType))) {
+ if (isDependingOnMainDexIndependents(appView.programDefinitionFor(clazz.superType, clazz))) {
isDependent = true;
} else {
- for (DexType interfaze : dexProgramClass.interfaces.values) {
- if (isDependingOnMainDexIndependents(app.programDefinitionFor(interfaze))) {
+ for (DexType interfaze : clazz.interfaces.values) {
+ if (isDependingOnMainDexIndependents(appView.programDefinitionFor(interfaze, clazz))) {
isDependent = true;
break;
}
@@ -227,9 +227,9 @@
}
if (isDependent) {
- dependentsOfMainDexIndependents.add(dexProgramClass);
+ dependentsOfMainDexIndependents.add(clazz);
} else {
- independentsFromMainDexIndependents.add(dexProgramClass);
+ independentsFromMainDexIndependents.add(clazz);
}
return isDependent;
}
@@ -245,12 +245,12 @@
private final Map<DexProgramClass, Collection<DexProgramClass>> directSubClasses;
private final Set<DexProgramClass> classes;
- DirectSubClassesInfo(DexApplication app, Set<DexProgramClass> classes) {
+ DirectSubClassesInfo(AppView<?> appView, Set<DexProgramClass> classes) {
Map<DexProgramClass, Collection<DexProgramClass>> directSubClasses = new HashMap<>();
for (DexProgramClass clazz : classes) {
- addDirectSubClass(app, classes, directSubClasses, clazz.superType, clazz);
+ addDirectSubClass(appView, classes, directSubClasses, clazz.superType, clazz);
for (DexType interfaze : clazz.interfaces.values) {
- addDirectSubClass(app, classes, directSubClasses, interfaze, clazz);
+ addDirectSubClass(appView, classes, directSubClasses, interfaze, clazz);
}
}
@@ -263,12 +263,13 @@
return directSubClasses.getOrDefault(clazz, Collections.emptyList());
}
- private static void addDirectSubClass(DexApplication app,
+ private static void addDirectSubClass(
+ AppView<?> appView,
Set<DexProgramClass> classes,
Map<DexProgramClass, Collection<DexProgramClass>> directSubClasses,
DexType superType,
DexProgramClass clazz) {
- DexProgramClass zuper = app.programDefinitionFor(superType);
+ DexProgramClass zuper = appView.programDefinitionFor(superType, clazz);
// Don't bother collecting subclasses info that we won't use.
if (zuper != null && classes.contains(zuper)) {
Collection<DexProgramClass> subClasses =
@@ -283,7 +284,7 @@
private final List<VirtualFile> dexes;
private final BitSet fullDex = new BitSet();
private final Set<DexProgramClass> classes;
- private final DexApplication app;
+ private final AppView<?> appView;
private int dexIndexOffset;
private final GraphLens graphLens;
private final InitClassLens initClassLens;
@@ -298,7 +299,7 @@
GraphLens graphLens,
InitClassLens initClassLens,
NamingLens namingLens,
- DexApplication app,
+ AppView<?> appView,
ExecutorService executorService) {
this.mainDex = mainDex;
this.dexes = dexes;
@@ -307,10 +308,10 @@
this.graphLens = graphLens;
this.initClassLens = initClassLens;
this.namingLens = namingLens;
- this.app = app;
+ this.appView = appView;
this.executorService = executorService;
- directSubClasses = new DirectSubClassesInfo(app, classes);
+ directSubClasses = new DirectSubClassesInfo(appView, classes);
}
public void distribute() {
@@ -378,7 +379,7 @@
private Collection<VirtualFile> assignGroup(ClassGroup group, List<VirtualFile> dexBlackList) {
VirtualFileCycler cycler =
- new VirtualFileCycler(dexes, graphLens, initClassLens, namingLens, dexIndexOffset);
+ new VirtualFileCycler(dexes, appView, graphLens, initClassLens, namingLens, dexIndexOffset);
if (group.members.isEmpty()) {
return Collections.emptyList();
} else if (group.canFitInOneDex()) {
@@ -427,7 +428,7 @@
Collection<VirtualFile> usedDex = new ArrayList<>();
VirtualFileCycler cycler =
- new VirtualFileCycler(dexes, graphLens, initClassLens, namingLens, dexIndexOffset);
+ new VirtualFileCycler(dexes, appView, graphLens, initClassLens, namingLens, dexIndexOffset);
// Don't modify input dexBlackList. Think about modifying the input collection considering this
// is private API.
Set<VirtualFile> currentBlackList = new HashSet<>(dexBlackList);
@@ -581,9 +582,9 @@
group.members.add(clazz);
// Check dependencies are added to the group.
- collectGroup(classes, group, app.programDefinitionFor(clazz.superType));
+ collectGroup(classes, group, appView.programDefinitionFor(clazz.superType, clazz));
for (DexType interfaze : clazz.interfaces.values) {
- collectGroup(classes, group, app.programDefinitionFor(interfaze));
+ collectGroup(classes, group, appView.programDefinitionFor(interfaze, clazz));
}
// Check that dependants are added to the group.
@@ -666,11 +667,11 @@
private boolean hasDirectInheritanceInCollection(DexProgramClass clazz,
Set<DexProgramClass> collection) {
- if (collection.contains(app.programDefinitionFor(clazz.superType))) {
+ if (collection.contains(appView.programDefinitionFor(clazz.superType, clazz))) {
return true;
}
for (DexType interfaze : clazz.interfaces.values) {
- if (collection.contains(app.programDefinitionFor(interfaze))) {
+ if (collection.contains(appView.programDefinitionFor(interfaze, clazz))) {
return true;
}
}
@@ -708,13 +709,13 @@
private DexProgramClass findOneRootInSetFrom(DexProgramClass searchFrom,
Set<DexProgramClass> classSet) {
- DexProgramClass zuper = app.programDefinitionFor(searchFrom.superType);
+ DexProgramClass zuper = appView.programDefinitionFor(searchFrom.superType, searchFrom);
if (classSet.contains(zuper)) {
return findOneRootInSetFrom(zuper, classSet);
}
for (DexType interfaceType : searchFrom.interfaces.values) {
- DexClass interfaceClass = app.definitionFor(interfaceType);
- if (classSet.contains(interfaceClass)) {
+ DexClass interfaceClass = appView.definitionFor(interfaceType);
+ if (interfaceClass.isProgramClass() && classSet.contains(interfaceClass.asProgramClass())) {
return findOneRootInSetFrom((DexProgramClass) interfaceClass, classSet);
}
}
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 b036d96..5e31d99 100644
--- a/src/main/java/com/android/tools/r8/dex/VirtualFile.java
+++ b/src/main/java/com/android/tools/r8/dex/VirtualFile.java
@@ -3,12 +3,14 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.dex;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+
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.graph.DexApplication;
+import com.android.tools.r8.graph.AppInfo;
+import com.android.tools.r8.graph.AppView;
import com.android.tools.r8.graph.DexCallSite;
-import com.android.tools.r8.graph.DexClass;
import com.android.tools.r8.graph.DexField;
import com.android.tools.r8.graph.DexItem;
import com.android.tools.r8.graph.DexItemFactory;
@@ -21,14 +23,15 @@
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.logging.Log;
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.utils.DescriptorUtils;
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Reporter;
-import com.android.tools.r8.utils.StringDiagnostic;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;
@@ -77,30 +80,38 @@
private final DexProgramClass primaryClass;
- VirtualFile(int id, GraphLens graphLens, InitClassLens initClassLens, NamingLens namingLens) {
- this(id, graphLens, initClassLens, namingLens, null, null);
+ VirtualFile(
+ int id,
+ AppView<?> appView,
+ GraphLens graphLens,
+ InitClassLens initClassLens,
+ NamingLens namingLens) {
+ this(id, appView, graphLens, initClassLens, namingLens, null, null);
}
VirtualFile(
int id,
+ AppView<?> appView,
GraphLens graphLens,
InitClassLens initClassLens,
NamingLens namingLens,
FeatureSplit featureSplit) {
- this(id, graphLens, initClassLens, namingLens, null, featureSplit);
+ this(id, appView, graphLens, initClassLens, namingLens, null, featureSplit);
}
private VirtualFile(
int id,
+ AppView<?> appView,
GraphLens graphLens,
InitClassLens initClassLens,
NamingLens namingLens,
DexProgramClass primaryClass) {
- this(id, graphLens, initClassLens, namingLens, primaryClass, null);
+ this(id, appView, graphLens, initClassLens, namingLens, primaryClass, null);
}
private VirtualFile(
int id,
+ AppView<?> appView,
GraphLens graphLens,
InitClassLens initClassLens,
NamingLens namingLens,
@@ -109,7 +120,7 @@
this.id = id;
this.indexedItems = new VirtualFileIndexedItemCollection(graphLens, initClassLens, namingLens);
this.transaction =
- new IndexedItemTransaction(indexedItems, graphLens, initClassLens, namingLens);
+ new IndexedItemTransaction(indexedItems, appView, graphLens, initClassLens, namingLens);
this.primaryClass = primaryClass;
this.featureSplit = featureSplit;
}
@@ -193,10 +204,11 @@
}
public ObjectToOffsetMapping computeMapping(
- DexApplication application, NamingLens namingLens, InitClassLens initClassLens) {
+ AppInfo appInfo, GraphLens graphLens, NamingLens namingLens, InitClassLens initClassLens) {
assert transaction.isEmpty();
return new ObjectToOffsetMapping(
- application,
+ appInfo,
+ graphLens,
namingLens,
initClassLens,
indexedItems.classes,
@@ -272,12 +284,12 @@
}
public abstract static class Distributor {
- protected final DexApplication application;
+ protected final AppView<?> appView;
protected final ApplicationWriter writer;
protected final List<VirtualFile> virtualFiles = new ArrayList<>();
Distributor(ApplicationWriter writer) {
- this.application = writer.application;
+ this.appView = writer.appView;
this.writer = writer;
}
@@ -304,11 +316,12 @@
HashMap<DexProgramClass, VirtualFile> files = new HashMap<>();
Collection<DexProgramClass> synthetics = new ArrayList<>();
// Assign dedicated virtual files for all program classes.
- for (DexProgramClass clazz : application.classes()) {
+ for (DexProgramClass clazz : appView.appInfo().classes()) {
if (!combineSyntheticClassesWithPrimaryClass || clazz.getSynthesizedFrom().isEmpty()) {
VirtualFile file =
new VirtualFile(
virtualFiles.size(),
+ writer.appView,
writer.graphLens,
writer.initClassLens,
writer.namingLens,
@@ -345,13 +358,15 @@
this.options = options;
// Create the primary dex file. The distribution will add more if needed.
- mainDexFile = new VirtualFile(0, writer.graphLens, writer.initClassLens, writer.namingLens);
+ mainDexFile =
+ new VirtualFile(
+ 0, writer.appView, writer.graphLens, writer.initClassLens, writer.namingLens);
assert virtualFiles.isEmpty();
virtualFiles.add(mainDexFile);
addMarkers(mainDexFile);
- classes = Sets.newHashSet(application.classes());
- originalNames = computeOriginalNameMapping(classes, application.getProguardMap());
+ classes = Sets.newHashSet(appView.appInfo().classes());
+ originalNames = computeOriginalNameMapping(classes, appView.appInfo().app().getProguardMap());
}
private void addMarkers(VirtualFile virtualFile) {
@@ -364,37 +379,30 @@
}
protected void fillForMainDexList(Set<DexProgramClass> classes) {
- if (!application.mainDexList.isEmpty()) {
- VirtualFile mainDexFile = virtualFiles.get(0);
- for (DexType type : application.mainDexList) {
- DexClass clazz = application.definitionFor(type);
- if (clazz != null && clazz.isProgramClass()) {
- DexProgramClass programClass = (DexProgramClass) clazz;
- mainDexFile.addClass(programClass);
- classes.remove(programClass);
- } else {
- if (!options.ignoreMainDexMissingClasses) {
- options.reporter.warning(
- new StringDiagnostic(
- "Application does not contain `"
- + type.toSourceString()
- + "` as referenced in main-dex-list."));
- }
- }
- mainDexFile.commitTransaction();
- }
- if (Log.ENABLED) {
- Log.info(
- VirtualFile.class,
- "Main dex classes: " + mainDexFile.transaction.getNumberOfClasses());
- Log.info(
- VirtualFile.class,
- "Main dex methods: " + mainDexFile.transaction.getNumberOfMethods());
- Log.info(
- VirtualFile.class, "Main dex fields: " + mainDexFile.transaction.getNumberOfFields());
- }
- mainDexFile.throwIfFull(true, options.reporter);
+ MainDexClasses mainDexClasses = appView.appInfo().getMainDexClasses();
+ if (mainDexClasses.isEmpty()) {
+ return;
}
+ VirtualFile mainDexFile = virtualFiles.get(0);
+ mainDexClasses.forEach(
+ type -> {
+ DexProgramClass clazz =
+ asProgramClassOrNull(appView.appInfo().definitionForWithoutExistenceAssert(type));
+ if (clazz != null) {
+ mainDexFile.addClass(clazz);
+ classes.remove(clazz);
+ }
+ mainDexFile.commitTransaction();
+ });
+ if (Log.ENABLED) {
+ Log.info(
+ VirtualFile.class, "Main dex classes: " + mainDexFile.transaction.getNumberOfClasses());
+ Log.info(
+ VirtualFile.class, "Main dex methods: " + mainDexFile.transaction.getNumberOfMethods());
+ Log.info(
+ VirtualFile.class, "Main dex fields: " + mainDexFile.transaction.getNumberOfFields());
+ }
+ mainDexFile.throwIfFull(true, options.reporter);
}
TreeSet<DexProgramClass> sortClassesByPackage(Set<DexProgramClass> classes,
@@ -437,7 +445,7 @@
// Pull out the classes that should go into feature splits.
Map<FeatureSplit, Set<DexProgramClass>> featureSplitClasses =
options.featureSplitConfiguration.getFeatureSplitClasses(
- classes, application.getProguardMap());
+ classes, appView.appInfo().app().getProguardMap());
if (featureSplitClasses.size() > 0) {
for (Set<DexProgramClass> featureClasses : featureSplitClasses.values()) {
classes.removeAll(featureClasses);
@@ -464,6 +472,7 @@
VirtualFile featureFile =
new VirtualFile(
0,
+ writer.appView,
writer.graphLens,
writer.initClassLens,
writer.namingLens,
@@ -476,9 +485,9 @@
new PackageSplitPopulator(
filesForDistribution,
+ appView,
featureClasses,
originalNames,
- application.dexItemFactory,
fillStrategy,
0,
writer.graphLens,
@@ -519,7 +528,8 @@
assert virtualFiles.size() == 1;
// The main dex file is filtered out, so ensure at least one file for the remaining classes.
virtualFiles.add(
- new VirtualFile(1, writer.graphLens, writer.initClassLens, writer.namingLens));
+ new VirtualFile(
+ 1, writer.appView, writer.graphLens, writer.initClassLens, writer.namingLens));
filesForDistribution = virtualFiles.subList(1, virtualFiles.size());
fileIndexOffset = 1;
}
@@ -536,7 +546,7 @@
writer.graphLens,
writer.initClassLens,
writer.namingLens,
- writer.application,
+ writer.appView,
executorService)
.distribute();
} else {
@@ -545,9 +555,9 @@
classes = sortClassesByPackage(classes, originalNames);
new PackageSplitPopulator(
filesForDistribution,
+ appView,
classes,
originalNames,
- application.dexItemFactory,
fillStrategy,
fileIndexOffset,
writer.graphLens,
@@ -695,6 +705,7 @@
private final GraphLens graphLens;
private final InitClassLens initClassLens;
private final NamingLens namingLens;
+ private final LensCodeRewriterUtils rewriter;
private final Set<DexProgramClass> classes = new LinkedHashSet<>();
private final Set<DexField> fields = new LinkedHashSet<>();
@@ -707,6 +718,7 @@
private IndexedItemTransaction(
VirtualFileIndexedItemCollection base,
+ AppView<?> appView,
GraphLens graphLens,
InitClassLens initClassLens,
NamingLens namingLens) {
@@ -714,6 +726,7 @@
this.graphLens = graphLens;
this.initClassLens = initClassLens;
this.namingLens = namingLens;
+ this.rewriter = new LensCodeRewriterUtils(appView, graphLens);
}
private <T extends DexItem> boolean maybeInsert(T item, Set<T> set, Set<T> baseSet) {
@@ -725,7 +738,7 @@
}
void addClassAndDependencies(DexProgramClass clazz) {
- clazz.collectIndexedItems(this);
+ clazz.collectIndexedItems(this, graphLens, rewriter);
}
@Override
@@ -855,6 +868,7 @@
static class VirtualFileCycler {
private final List<VirtualFile> files;
+ private final AppView<?> appView;
private final GraphLens graphLens;
private final InitClassLens initClassLens;
private final NamingLens namingLens;
@@ -866,11 +880,13 @@
VirtualFileCycler(
List<VirtualFile> files,
+ AppView<?> appView,
GraphLens graphLens,
InitClassLens initClassLens,
NamingLens namingLens,
int fileIndexOffset) {
this.files = files;
+ this.appView = appView;
this.graphLens = graphLens;
this.initClassLens = initClassLens;
this.namingLens = namingLens;
@@ -904,7 +920,8 @@
return activeFiles.next();
} else {
VirtualFile newFile =
- new VirtualFile(nextFileId++, graphLens, initClassLens, namingLens, featuresplit);
+ new VirtualFile(
+ nextFileId++, appView, graphLens, initClassLens, namingLens, featuresplit);
files.add(newFile);
allFilesCyclic = Iterators.cycle(files);
return newFile;
@@ -936,7 +953,8 @@
VirtualFile addFile() {
VirtualFile newFile =
- new VirtualFile(nextFileId++, graphLens, initClassLens, namingLens, featuresplit);
+ new VirtualFile(
+ nextFileId++, appView, graphLens, initClassLens, namingLens, featuresplit);
files.add(newFile);
reset();
@@ -977,9 +995,9 @@
PackageSplitPopulator(
List<VirtualFile> files,
+ AppView<?> appView,
Set<DexProgramClass> classes,
Map<DexProgramClass, String> originalNames,
- DexItemFactory dexItemFactory,
FillStrategy fillStrategy,
int fileIndexOffset,
GraphLens graphLens,
@@ -988,11 +1006,12 @@
InternalOptions options) {
this.classes = new ArrayList<>(classes);
this.originalNames = originalNames;
- this.dexItemFactory = dexItemFactory;
+ this.dexItemFactory = appView.dexItemFactory();
this.fillStrategy = fillStrategy;
this.options = options;
this.cycler =
- new VirtualFileCycler(files, graphLens, initClassLens, namingLens, fileIndexOffset);
+ new VirtualFileCycler(
+ files, appView, graphLens, initClassLens, namingLens, fileIndexOffset);
}
static boolean coveredByPrefix(String originalName, String currentPrefix) {
diff --git a/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java b/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java
new file mode 100644
index 0000000..e078248
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/AbstractAccessContexts.java
@@ -0,0 +1,366 @@
+// 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.errors.Unreachable;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+import java.util.IdentityHashMap;
+import java.util.Map;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+/**
+ * For a concrete field, stores the contexts in which the field is accessed.
+ *
+ * <p>If the concrete field does not have any accesses, then {@link EmptyAccessContexts}.
+ *
+ * <p>If nothing is nothing about the accesses to the concrete field, then {@link
+ * UnknownAccessContexts}.
+ *
+ * <p>Otherwise, the concrete contexts in which the field is accessed is maintained by {@link
+ * ConcreteAccessContexts}. The access contexts are qualified by the field reference they access.
+ *
+ * <p>Example: If a field `int Foo.field` is accessed directly in `void Main.direct()` and
+ * indirectly via a non-rebound reference `int FooSub.field` in `void Main.indirect()`, then the
+ * collection is:
+ *
+ * <pre>
+ * ConcreteAccessContexts {
+ * `int Foo.field` -> { `void Main.direct()` }
+ * `int FooSub.field` -> { `void Main.indirect()` }
+ * }
+ * </pre>
+ */
+public abstract class AbstractAccessContexts {
+
+ abstract void flattenAccessContexts(DexField field);
+
+ abstract void forEachAccessContext(Consumer<ProgramMethod> consumer);
+
+ /**
+ * Returns true if this field is written by a method for which {@param predicate} returns true.
+ */
+ abstract boolean isAccessedInMethodSatisfying(Predicate<ProgramMethod> predicate);
+
+ /**
+ * Returns true if this field is only written by methods for which {@param predicate} returns
+ * true.
+ */
+ abstract boolean isAccessedOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate);
+
+ /**
+ * Returns true if this field is written by a method in the program other than {@param method}.
+ */
+ abstract boolean isAccessedOutside(DexEncodedMethod method);
+
+ abstract int getNumberOfAccessContexts();
+
+ public boolean isBottom() {
+ return false;
+ }
+
+ public boolean isConcrete() {
+ return false;
+ }
+
+ abstract boolean isEmpty();
+
+ public ConcreteAccessContexts asConcrete() {
+ return null;
+ }
+
+ public boolean isTop() {
+ return false;
+ }
+
+ abstract AbstractAccessContexts rewrittenWithLens(
+ DexDefinitionSupplier definitions, GraphLens lens);
+
+ public static EmptyAccessContexts empty() {
+ return EmptyAccessContexts.getInstance();
+ }
+
+ public static UnknownAccessContexts unknown() {
+ return UnknownAccessContexts.getInstance();
+ }
+
+ public static class EmptyAccessContexts extends AbstractAccessContexts {
+
+ public static EmptyAccessContexts INSTANCE = new EmptyAccessContexts();
+
+ private EmptyAccessContexts() {}
+
+ public static EmptyAccessContexts getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ void flattenAccessContexts(DexField field) {
+ // Intentionally empty.
+ }
+
+ @Override
+ void forEachAccessContext(Consumer<ProgramMethod> consumer) {
+ // Intentionally empty.
+ }
+
+ @Override
+ boolean isAccessedInMethodSatisfying(Predicate<ProgramMethod> predicate) {
+ return false;
+ }
+
+ @Override
+ boolean isAccessedOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
+ return true;
+ }
+
+ @Override
+ boolean isAccessedOutside(DexEncodedMethod method) {
+ return false;
+ }
+
+ @Override
+ int getNumberOfAccessContexts() {
+ return 0;
+ }
+
+ @Override
+ public boolean isBottom() {
+ return true;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return true;
+ }
+
+ @Override
+ AbstractAccessContexts rewrittenWithLens(DexDefinitionSupplier definitions, GraphLens lens) {
+ return this;
+ }
+ }
+
+ public static class ConcreteAccessContexts extends AbstractAccessContexts {
+
+ private final Map<DexField, ProgramMethodSet> accessesWithContexts;
+
+ public ConcreteAccessContexts() {
+ this(new IdentityHashMap<>());
+ }
+
+ public ConcreteAccessContexts(Map<DexField, ProgramMethodSet> accessesWithContexts) {
+ this.accessesWithContexts = accessesWithContexts;
+ }
+
+ void forEachAccess(Consumer<DexField> consumer, Predicate<DexField> predicate) {
+ if (accessesWithContexts != null) {
+ accessesWithContexts.forEach(
+ (access, contexts) -> {
+ if (predicate.test(access)) {
+ consumer.accept(access);
+ }
+ });
+ }
+ }
+
+ @Override
+ void forEachAccessContext(Consumer<ProgramMethod> consumer) {
+ // There can be indirect reads and writes of the same field reference, so we need to keep
+ // track
+ // of the previously-seen indirect accesses to avoid reporting duplicates.
+ ProgramMethodSet visited = ProgramMethodSet.create();
+ if (accessesWithContexts != null) {
+ for (ProgramMethodSet encodedAccessContexts : accessesWithContexts.values()) {
+ for (ProgramMethod encodedAccessContext : encodedAccessContexts) {
+ if (visited.add(encodedAccessContext)) {
+ consumer.accept(encodedAccessContext);
+ }
+ }
+ }
+ }
+ }
+
+ Map<DexField, ProgramMethodSet> getAccessesWithContexts() {
+ return accessesWithContexts;
+ }
+
+ @Override
+ int getNumberOfAccessContexts() {
+ if (accessesWithContexts.size() == 1) {
+ return accessesWithContexts.values().iterator().next().size();
+ }
+ throw new Unreachable(
+ "Should only be querying the number of access contexts after flattening");
+ }
+
+ ProgramMethod getUniqueAccessContext() {
+ if (accessesWithContexts != null && accessesWithContexts.size() == 1) {
+ ProgramMethodSet contexts = accessesWithContexts.values().iterator().next();
+ if (contexts.size() == 1) {
+ return contexts.iterator().next();
+ }
+ }
+ return null;
+ }
+
+ @Override
+ void flattenAccessContexts(DexField field) {
+ if (accessesWithContexts != null) {
+ ProgramMethodSet flattenedAccessContexts =
+ accessesWithContexts.computeIfAbsent(field, ignore -> ProgramMethodSet.create());
+ accessesWithContexts.forEach(
+ (access, contexts) -> {
+ if (access != field) {
+ flattenedAccessContexts.addAll(contexts);
+ }
+ });
+ accessesWithContexts.clear();
+ if (!flattenedAccessContexts.isEmpty()) {
+ accessesWithContexts.put(field, flattenedAccessContexts);
+ }
+ assert accessesWithContexts.size() <= 1;
+ }
+ }
+
+ /**
+ * Returns true if this field is written by a method for which {@param predicate} returns true.
+ */
+ @Override
+ public boolean isAccessedInMethodSatisfying(Predicate<ProgramMethod> predicate) {
+ for (ProgramMethodSet encodedWriteContexts : accessesWithContexts.values()) {
+ for (ProgramMethod encodedWriteContext : encodedWriteContexts) {
+ if (predicate.test(encodedWriteContext)) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Returns true if this field is only written by methods for which {@param predicate} returns
+ * true.
+ */
+ @Override
+ public boolean isAccessedOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
+ for (ProgramMethodSet encodedWriteContexts : accessesWithContexts.values()) {
+ for (ProgramMethod encodedWriteContext : encodedWriteContexts) {
+ if (!predicate.test(encodedWriteContext)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Returns true if this field is written by a method in the program other than {@param method}.
+ */
+ @Override
+ public boolean isAccessedOutside(DexEncodedMethod method) {
+ for (ProgramMethodSet encodedWriteContexts : accessesWithContexts.values()) {
+ for (ProgramMethod encodedWriteContext : encodedWriteContexts) {
+ if (encodedWriteContext.getDefinition() != method) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isConcrete() {
+ return true;
+ }
+
+ @Override
+ public ConcreteAccessContexts asConcrete() {
+ return this;
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return accessesWithContexts.isEmpty();
+ }
+
+ boolean recordAccess(DexField access, ProgramMethod context) {
+ return accessesWithContexts
+ .computeIfAbsent(access, ignore -> ProgramMethodSet.create())
+ .add(context);
+ }
+
+ @Override
+ ConcreteAccessContexts rewrittenWithLens(DexDefinitionSupplier definitions, GraphLens lens) {
+ Map<DexField, ProgramMethodSet> newAccessesWithContexts = new IdentityHashMap<>();
+ accessesWithContexts.forEach(
+ (access, contexts) -> {
+ ProgramMethodSet newContexts =
+ newAccessesWithContexts.computeIfAbsent(
+ lens.lookupField(access), ignore -> ProgramMethodSet.create());
+ for (ProgramMethod context : contexts) {
+ newContexts.add(lens.mapProgramMethod(context, definitions));
+ }
+ });
+ return new ConcreteAccessContexts(newAccessesWithContexts);
+ }
+ }
+
+ public static class UnknownAccessContexts extends AbstractAccessContexts {
+
+ public static UnknownAccessContexts INSTANCE = new UnknownAccessContexts();
+
+ private UnknownAccessContexts() {}
+
+ public static UnknownAccessContexts getInstance() {
+ return INSTANCE;
+ }
+
+ @Override
+ void flattenAccessContexts(DexField field) {
+ // Intentionally empty.
+ }
+
+ @Override
+ void forEachAccessContext(Consumer<ProgramMethod> consumer) {
+ throw new Unreachable("Should never be iterating the access contexts when they are unknown");
+ }
+
+ @Override
+ boolean isAccessedInMethodSatisfying(Predicate<ProgramMethod> predicate) {
+ return true;
+ }
+
+ @Override
+ boolean isAccessedOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
+ return false;
+ }
+
+ @Override
+ boolean isAccessedOutside(DexEncodedMethod method) {
+ return true;
+ }
+
+ @Override
+ int getNumberOfAccessContexts() {
+ throw new Unreachable(
+ "Should never be querying the number of access contexts when they are unknown");
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return false;
+ }
+
+ @Override
+ public boolean isTop() {
+ return true;
+ }
+
+ @Override
+ AbstractAccessContexts rewrittenWithLens(DexDefinitionSupplier definitions, GraphLens lens) {
+ return this;
+ }
+ }
+}
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 59239db..c49eb28 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfo.java
@@ -8,6 +8,7 @@
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.utils.BooleanBox;
import com.android.tools.r8.utils.InternalOptions;
import java.util.Collection;
@@ -16,6 +17,7 @@
private final DexApplication app;
private final DexItemFactory dexItemFactory;
+ private final MainDexClasses mainDexClasses;
private final SyntheticItems syntheticItems;
// Set when a new AppInfo replaces a previous one. All public methods should verify that the
@@ -23,23 +25,40 @@
private final BooleanBox obsolete;
public static AppInfo createInitialAppInfo(DexApplication application) {
- return new AppInfo(application, SyntheticItems.createInitialSyntheticItems(), new BooleanBox());
+ return createInitialAppInfo(application, MainDexClasses.createEmptyMainDexClasses());
}
- public AppInfo(DexApplication application, SyntheticItems.CommittedItems committedItems) {
- this(application, committedItems.toSyntheticItems(), new BooleanBox());
+ public static AppInfo createInitialAppInfo(
+ DexApplication application, MainDexClasses mainDexClasses) {
+ return new AppInfo(
+ application,
+ mainDexClasses,
+ SyntheticItems.createInitialSyntheticItems(),
+ new BooleanBox());
+ }
+
+ public AppInfo(
+ DexApplication application,
+ MainDexClasses mainDexClasses,
+ SyntheticItems.CommittedItems committedItems) {
+ this(application, mainDexClasses, committedItems.toSyntheticItems(), 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.syntheticItems, appInfo.obsolete);
+ this(appInfo.app, appInfo.mainDexClasses, appInfo.syntheticItems, appInfo.obsolete);
assert witness != null;
}
- private AppInfo(DexApplication application, SyntheticItems syntheticItems, BooleanBox obsolete) {
+ private AppInfo(
+ DexApplication application,
+ MainDexClasses mainDexClasses,
+ SyntheticItems syntheticItems,
+ BooleanBox obsolete) {
this.app = application;
this.dexItemFactory = application.dexItemFactory;
+ this.mainDexClasses = mainDexClasses;
this.syntheticItems = syntheticItems;
this.obsolete = obsolete;
}
@@ -76,13 +95,20 @@
return dexItemFactory;
}
+ public MainDexClasses getMainDexClasses() {
+ return mainDexClasses;
+ }
+
public SyntheticItems getSyntheticItems() {
return syntheticItems;
}
- public void addSynthesizedClass(DexProgramClass clazz) {
+ public void addSynthesizedClass(DexProgramClass clazz, boolean addToMainDexClasses) {
assert checkIfObsolete();
syntheticItems.addSyntheticClass(clazz);
+ if (addToMainDexClasses && !mainDexClasses.isEmpty()) {
+ mainDexClasses.add(clazz);
+ }
}
public Collection<DexProgramClass> synthesizedClasses() {
@@ -189,11 +215,6 @@
return null;
}
- public boolean isInMainDexList(DexType type) {
- assert checkIfObsolete();
- return app.mainDexList.contains(type);
- }
-
public final FieldResolutionResult resolveField(DexField field, ProgramMethod context) {
return resolveFieldOn(field.holder, field, context);
}
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 f1b0dc2..68ce78b 100644
--- a/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
+++ b/src/main/java/com/android/tools/r8/graph/AppInfoWithClassHierarchy.java
@@ -15,6 +15,7 @@
import com.android.tools.r8.graph.ResolutionResult.NoSuchMethodResult;
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.utils.ListUtils;
import com.android.tools.r8.utils.SetUtils;
import com.android.tools.r8.utils.TraversalContinuation;
@@ -46,15 +47,19 @@
}
public static AppInfoWithClassHierarchy createInitialAppInfoWithClassHierarchy(
- DexApplication application) {
+ DexApplication application, MainDexClasses mainDexClasses) {
return new AppInfoWithClassHierarchy(
- application, SyntheticItems.createInitialSyntheticItems().commit(application));
+ application,
+ mainDexClasses,
+ SyntheticItems.createInitialSyntheticItems().commit(application));
}
// For AppInfoWithLiveness.
protected AppInfoWithClassHierarchy(
- DexApplication application, SyntheticItems.CommittedItems committedItems) {
- super(application, committedItems);
+ DexApplication application,
+ MainDexClasses mainDexClasses,
+ SyntheticItems.CommittedItems committedItems) {
+ super(application, mainDexClasses, committedItems);
}
// For desugaring.
@@ -69,7 +74,8 @@
public AppInfoWithClassHierarchy rebuild(Function<DexApplication, DexApplication> fn) {
DexApplication application = fn.apply(app());
- return new AppInfoWithClassHierarchy(application, getSyntheticItems().commit(application));
+ return new AppInfoWithClassHierarchy(
+ application, getMainDexClasses(), getSyntheticItems().commit(application));
}
@Override
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 d0a3643..2a181bc 100644
--- a/src/main/java/com/android/tools/r8/graph/AppView.java
+++ b/src/main/java/com/android/tools/r8/graph/AppView.java
@@ -25,6 +25,7 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.KeepInfoCollection;
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.utils.InternalOptions;
import com.android.tools.r8.utils.OptionalBool;
@@ -129,8 +130,14 @@
}
public static AppView<AppInfoWithClassHierarchy> createForR8(DexApplication application) {
+ return createForR8(application, MainDexClasses.createEmptyMainDexClasses());
+ }
+
+ public static AppView<AppInfoWithClassHierarchy> createForR8(
+ DexApplication application, MainDexClasses mainDexClasses) {
AppInfoWithClassHierarchy appInfo =
- AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(application);
+ AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
+ application, mainDexClasses);
return new AppView<>(
appInfo, WholeProgramOptimizations.ON, defaultPrefixRewritingMapper(appInfo));
}
diff --git a/src/main/java/com/android/tools/r8/graph/CfCode.java b/src/main/java/com/android/tools/r8/graph/CfCode.java
index c40931a..b74a480 100644
--- a/src/main/java/com/android/tools/r8/graph/CfCode.java
+++ b/src/main/java/com/android/tools/r8/graph/CfCode.java
@@ -24,6 +24,7 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.CfSourceCode;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.ir.optimize.Inliner.ConstraintWithTarget;
import com.android.tools.r8.ir.optimize.InliningConstraints;
@@ -39,6 +40,7 @@
import java.util.BitSet;
import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Map.Entry;
import org.objectweb.asm.Label;
import org.objectweb.asm.MethodVisitor;
@@ -199,18 +201,21 @@
}
public void write(
- DexEncodedMethod method,
- MethodVisitor visitor,
- NamingLens namingLens,
+ ProgramMethod method,
+ int classFileVersion,
AppView<?> appView,
- int classFileVersion) {
+ NamingLens namingLens,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
GraphLens graphLens = appView.graphLens();
InitClassLens initClassLens = appView.initClassLens();
InternalOptions options = appView.options();
CfLabel parameterLabel = null;
- if (shouldAddParameterNames(method, appView)) {
+ if (shouldAddParameterNames(method.getDefinition(), appView)) {
parameterLabel = new CfLabel();
- parameterLabel.write(visitor, graphLens, initClassLens, namingLens);
+ parameterLabel.write(
+ method, dexItemFactory, graphLens, initClassLens, namingLens, rewriter, visitor);
}
for (CfInstruction instruction : instructions) {
if (instruction instanceof CfFrame
@@ -218,7 +223,8 @@
|| (classFileVersion == V1_6 && !options.shouldKeepStackMapTable()))) {
continue;
}
- instruction.write(visitor, graphLens, initClassLens, namingLens);
+ instruction.write(
+ method, dexItemFactory, graphLens, initClassLens, namingLens, rewriter, visitor);
}
visitor.visitEnd();
visitor.visitMaxs(maxStack, maxLocals);
@@ -227,19 +233,21 @@
Label end = tryCatch.end.getLabel();
for (int i = 0; i < tryCatch.guards.size(); i++) {
DexType guard = tryCatch.guards.get(i);
+ DexType rewrittenGuard = graphLens.lookupType(guard);
Label target = tryCatch.targets.get(i).getLabel();
visitor.visitTryCatchBlock(
start,
end,
target,
- guard == options.itemFactory.throwableType
+ rewrittenGuard == options.itemFactory.throwableType
? null
- : namingLens.lookupInternalName(guard));
+ : namingLens.lookupInternalName(rewrittenGuard));
}
}
if (parameterLabel != null) {
assert localVariables.isEmpty();
- for (Entry<Integer, DebugLocalInfo> entry : method.getParameterInfo().entrySet()) {
+ Map<Integer, DebugLocalInfo> parameterInfo = method.getDefinition().getParameterInfo();
+ for (Entry<Integer, DebugLocalInfo> entry : parameterInfo.entrySet()) {
writeLocalVariableEntry(
visitor, namingLens, entry.getValue(), parameterLabel, parameterLabel, entry.getKey());
}
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 d6d69a6..67870ab 100644
--- a/src/main/java/com/android/tools/r8/graph/DexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DexApplication.java
@@ -14,20 +14,15 @@
import com.android.tools.r8.utils.ProgramClassCollection;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
-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.Set;
public abstract class DexApplication {
public final ImmutableList<DataResourceProvider> dataResourceProviders;
- public final ImmutableSet<DexType> mainDexList;
-
private final ClassNameMapper proguardMap;
public final Timing timing;
@@ -42,13 +37,11 @@
DexApplication(
ClassNameMapper proguardMap,
ImmutableList<DataResourceProvider> dataResourceProviders,
- ImmutableSet<DexType> mainDexList,
InternalOptions options,
DexString highestSortingString,
Timing timing) {
this.proguardMap = proguardMap;
this.dataResourceProviders = dataResourceProviders;
- this.mainDexList = mainDexList;
this.options = options;
this.dexItemFactory = options.itemFactory;
this.highestSortingString = highestSortingString;
@@ -57,6 +50,22 @@
public abstract Builder<?> builder();
+ public DexDefinitionSupplier getDefinitionsSupplier(
+ SyntheticDefinitionsProvider syntheticDefinitionsProvider) {
+ DexApplication self = this;
+ return new DexDefinitionSupplier() {
+ @Override
+ public DexClass definitionFor(DexType type) {
+ return syntheticDefinitionsProvider.definitionFor(type, self::definitionFor);
+ }
+
+ @Override
+ public DexItemFactory dexItemFactory() {
+ return self.dexItemFactory;
+ }
+ };
+ }
+
// Reorder classes randomly. Note that the order of classes in program or library
// class collections should not matter for compilation of valid code and when running
// with assertions enabled we reorder the classes randomly to catch possible issues.
@@ -133,7 +142,6 @@
final Timing timing;
DexString highestSortingString;
- final Set<DexType> mainDexList = Sets.newIdentityHashSet();
private final Collection<DexProgramClass> synthesizedClasses;
public Builder(InternalOptions options, Timing timing) {
@@ -153,7 +161,6 @@
highestSortingString = application.highestSortingString;
options = application.options;
dexItemFactory = application.dexItemFactory;
- mainDexList.addAll(application.mainDexList);
synthesizedClasses = new ArrayList<>();
}
@@ -185,14 +192,10 @@
return self();
}
- public synchronized T addSynthesizedClass(
- DexProgramClass synthesizedClass, boolean addToMainDexList) {
+ public synchronized T addSynthesizedClass(DexProgramClass synthesizedClass) {
assert synthesizedClass.isProgramClass() : "All synthesized classes must be program classes";
addProgramClass(synthesizedClass);
synthesizedClasses.add(synthesizedClass);
- if (addToMainDexList && !mainDexList.isEmpty()) {
- mainDexList.add(synthesizedClass.type);
- }
return self();
}
@@ -204,20 +207,6 @@
return synthesizedClasses;
}
- public Set<DexType> getMainDexList() {
- return mainDexList;
- }
-
- public Builder<T> addToMainDexList(DexType mainDex) {
- mainDexList.add(mainDex);
- return this;
- }
-
- public Builder<T> addToMainDexList(Collection<DexType> mainDexList) {
- this.mainDexList.addAll(mainDexList);
- return this;
- }
-
public abstract DexApplication build();
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexCode.java b/src/main/java/com/android/tools/r8/graph/DexCode.java
index 6716297..b8a1e8f 100644
--- a/src/main/java/com/android/tools/r8/graph/DexCode.java
+++ b/src/main/java/com/android/tools/r8/graph/DexCode.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.ir.code.Position;
import com.android.tools.r8.ir.conversion.DexSourceCode;
import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.naming.ClassNameMapper;
import com.android.tools.r8.origin.Origin;
@@ -403,11 +404,15 @@
return builder.toString();
}
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems,
+ ProgramMethod context,
+ GraphLens graphLens,
+ LensCodeRewriterUtils rewriter) {
highestSortingString = null;
for (Instruction insn : instructions) {
assert !insn.isDexItemBasedConstString();
- insn.collectIndexedItems(indexedItems);
+ insn.collectIndexedItems(indexedItems, context, graphLens, rewriter);
if (insn.isConstString()) {
updateHighestSortingString(insn.asConstString().getString());
} else if (insn.isConstStringJumbo()) {
@@ -415,11 +420,11 @@
}
}
if (debugInfo != null) {
- getDebugInfoForWriting().collectIndexedItems(indexedItems);
+ getDebugInfoForWriting().collectIndexedItems(indexedItems, graphLens);
}
if (handlers != null) {
for (TryHandler handler : handlers) {
- handler.collectIndexedItems(indexedItems);
+ handler.collectIndexedItems(indexedItems, graphLens);
}
}
}
@@ -548,9 +553,9 @@
return false;
}
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
for (TypeAddrPair pair : pairs) {
- pair.collectIndexedItems(indexedItems);
+ pair.collectIndexedItems(indexedItems, graphLens);
}
}
@@ -590,8 +595,9 @@
this.addr = addr;
}
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- type.collectIndexedItems(indexedItems);
+ public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
+ DexType rewritten = graphLens.lookupType(type);
+ rewritten.collectIndexedItems(indexedItems);
}
@Override
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
index 20fd6e6..0e59082 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugEvent.java
@@ -13,7 +13,7 @@
abstract public class DexDebugEvent extends DexItem {
public static final DexDebugEvent[] EMPTY_ARRAY = {};
- public void collectIndexedItems(IndexedItemCollection collection) {
+ public void collectIndexedItems(IndexedItemCollection collection, GraphLens graphLens) {
// Empty by default.
}
@@ -220,12 +220,13 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection collection) {
+ public void collectIndexedItems(IndexedItemCollection collection, GraphLens graphLens) {
if (name != null) {
name.collectIndexedItems(collection);
}
if (type != null) {
- type.collectIndexedItems(collection);
+ DexType rewritten = graphLens.lookupType(type);
+ rewritten.collectIndexedItems(collection);
}
if (signature != null) {
signature.collectIndexedItems(collection);
@@ -359,7 +360,7 @@
}
@Override
- public void collectIndexedItems(IndexedItemCollection collection) {
+ public void collectIndexedItems(IndexedItemCollection collection, GraphLens graphLens) {
fileName.collectIndexedItems(collection);
}
diff --git a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
index 51ad23c..ed4f2c5 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDebugInfo.java
@@ -54,14 +54,14 @@
return false;
}
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(IndexedItemCollection indexedItems, GraphLens graphLens) {
for (DexString parameter : parameters) {
if (parameter != null) {
parameter.collectIndexedItems(indexedItems);
}
}
for (DexDebugEvent event : events) {
- event.collectIndexedItems(indexedItems);
+ event.collectIndexedItems(indexedItems, graphLens);
}
}
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 cc91bcd..9391a83 100644
--- a/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
+++ b/src/main/java/com/android/tools/r8/graph/DexDefinitionSupplier.java
@@ -31,6 +31,10 @@
return type == context.type ? context : contextIndependentDefinitionFor(type);
}
+ default DexClass definitionFor(DexType type, ProgramMethod context) {
+ return definitionFor(type, context.getHolder());
+ }
+
/**
* Lookup for the program definition of a type from a given context.
*
diff --git a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
index 4b6fd50..7683f12 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedField.java
@@ -7,7 +7,6 @@
import static com.android.tools.r8.ir.analysis.type.Nullability.maybeNull;
import static com.android.tools.r8.kotlin.KotlinMetadataUtils.NO_KOTLIN_INFO;
-import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
@@ -87,14 +86,6 @@
this.kotlinMemberInfo = kotlinMemberInfo;
}
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- field.collectIndexedItems(indexedItems);
- annotations().collectIndexedItems(indexedItems);
- if (accessFlags.isStatic()) {
- getStaticValue().collectIndexedItems(indexedItems);
- }
- }
-
@Override
void collectMixedSectionItems(MixedSectionCollection mixedItems) {
annotations().collectMixedSectionItems(mixedItems);
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 ce6934a..2ca1b48 100644
--- a/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexEncodedMethod.java
@@ -13,24 +13,30 @@
import static com.android.tools.r8.kotlin.KotlinMetadataUtils.NO_KOTLIN_INFO;
import com.android.tools.r8.cf.code.CfConstNull;
+import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfConstString;
+import com.android.tools.r8.cf.code.CfInstanceOf;
import com.android.tools.r8.cf.code.CfInstruction;
import com.android.tools.r8.cf.code.CfInvoke;
import com.android.tools.r8.cf.code.CfLoad;
+import com.android.tools.r8.cf.code.CfLogicalBinop;
import com.android.tools.r8.cf.code.CfNew;
+import com.android.tools.r8.cf.code.CfReturn;
import com.android.tools.r8.cf.code.CfStackInstruction;
import com.android.tools.r8.cf.code.CfStackInstruction.Opcode;
import com.android.tools.r8.cf.code.CfStore;
import com.android.tools.r8.cf.code.CfThrow;
import com.android.tools.r8.code.Const;
import com.android.tools.r8.code.ConstString;
+import com.android.tools.r8.code.InstanceOf;
import com.android.tools.r8.code.Instruction;
import com.android.tools.r8.code.InvokeDirect;
import com.android.tools.r8.code.InvokeStatic;
import com.android.tools.r8.code.NewInstance;
+import com.android.tools.r8.code.Return;
import com.android.tools.r8.code.Throw;
+import com.android.tools.r8.code.XorIntLit8;
import com.android.tools.r8.dex.Constants;
-import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.JumboStringRewriter;
import com.android.tools.r8.dex.MethodToCodeObjectMapping;
import com.android.tools.r8.dex.MixedSectionCollection;
@@ -38,6 +44,7 @@
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.Invoke;
+import com.android.tools.r8.ir.code.NumericType;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.conversion.DexBuilder;
import com.android.tools.r8.ir.desugar.NestBasedAccessDesugaring.DexFieldWithAccess;
@@ -61,6 +68,7 @@
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.shaking.AnnotationRemover;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.BooleanUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.OptionalBool;
import com.android.tools.r8.utils.Pair;
@@ -648,20 +656,6 @@
return "Encoded method " + method;
}
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
- checkIfObsolete();
- this.method.collectIndexedItems(indexedItems);
- if (code != null) {
- if (code.isDexCode()) {
- code.asDexCode().collectIndexedItems(indexedItems);
- } else {
- assert false;
- }
- }
- annotations().collectIndexedItems(indexedItems);
- parameterAnnotationsList.collectIndexedItems(indexedItems);
- }
-
@Override
void collectMixedSectionItems(MixedSectionCollection mixedItems) {
mixedItems.visit(this);
@@ -850,10 +844,46 @@
}
public DexCode buildEmptyThrowingDexCode() {
- Instruction insn[] = {new Const(0, 0), new Throw(0)};
+ Instruction[] insn = {new Const(0, 0), new Throw(0)};
return generateCodeFromTemplate(1, 0, insn);
}
+ public Code buildInstanceOfCode(DexType type, boolean negate, InternalOptions options) {
+ return options.isGeneratingClassFiles()
+ ? buildInstanceOfCfCode(type, negate)
+ : buildInstanceOfDexCode(type, negate);
+ }
+
+ public CfCode buildInstanceOfCfCode(DexType type, boolean negate) {
+ CfInstruction[] instructions = new CfInstruction[3 + BooleanUtils.intValue(negate) * 2];
+ int i = 0;
+ instructions[i++] = new CfLoad(ValueType.OBJECT, 0);
+ instructions[i++] = new CfInstanceOf(type);
+ if (negate) {
+ instructions[i++] = new CfConstNumber(1, ValueType.INT);
+ instructions[i++] = new CfLogicalBinop(CfLogicalBinop.Opcode.Xor, NumericType.INT);
+ }
+ instructions[i] = new CfReturn(ValueType.INT);
+ return new CfCode(
+ method.holder,
+ 1 + BooleanUtils.intValue(negate),
+ method.getArity() + 1,
+ Arrays.asList(instructions),
+ Collections.emptyList(),
+ Collections.emptyList());
+ }
+
+ public DexCode buildInstanceOfDexCode(DexType type, boolean negate) {
+ Instruction[] instructions = new Instruction[2 + BooleanUtils.intValue(negate)];
+ int i = 0;
+ instructions[i++] = new InstanceOf(0, 0, type);
+ if (negate) {
+ instructions[i++] = new XorIntLit8(0, 0, 1);
+ }
+ instructions[i] = new Return(0);
+ return generateCodeFromTemplate(1, 0, instructions);
+ }
+
public DexEncodedMethod toMethodThatLogsError(AppView<?> appView) {
if (appView.options().isGeneratingDex()) {
return toMethodThatLogsErrorDexCode(appView.dexItemFactory());
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 999f261..493bea3 100644
--- a/src/main/java/com/android/tools/r8/graph/DexMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/DexMethod.java
@@ -31,6 +31,10 @@
}
}
+ public DexString getName() {
+ return name;
+ }
+
public DexTypeList getParameters() {
return proto.parameters;
}
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 90c37ed..a285398 100644
--- a/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
+++ b/src/main/java/com/android/tools/r8/graph/DexProgramClass.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.dex.MixedSectionCollection;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.kotlin.KotlinClassLevelInfo;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.origin.Origin;
@@ -233,7 +234,8 @@
return originKind == Kind.CF;
}
- public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems, GraphLens graphLens, LensCodeRewriterUtils rewriter) {
if (indexedItems.addClass(this)) {
type.collectIndexedItems(indexedItems);
if (superType != null) {
@@ -254,8 +256,8 @@
for (InnerClassAttribute attribute : getInnerClasses()) {
attribute.collectIndexedItems(indexedItems);
}
- forEachField(field -> field.collectIndexedItems(indexedItems));
- forEachMethod(method -> method.collectIndexedItems(indexedItems));
+ forEachProgramField(field -> field.collectIndexedItems(indexedItems));
+ forEachProgramMethod(method -> method.collectIndexedItems(indexedItems, graphLens, rewriter));
}
}
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 81c4dc5..fc14405 100644
--- a/src/main/java/com/android/tools/r8/graph/DexType.java
+++ b/src/main/java/com/android/tools/r8/graph/DexType.java
@@ -286,21 +286,37 @@
// TODO(b/158159959): Remove usage of name-based identification.
public boolean isD8R8SynthesizedClassType() {
String name = toSourceString();
- return name.contains(COMPANION_CLASS_NAME_SUFFIX)
- || name.contains(ENUM_UNBOXING_UTILITY_CLASS_NAME)
+ // The synthesized classes listed here must always be unique to a program context and thus
+ // never duplicated for distinct inputs.
+ return
+ // Hygienic suffix.
+ name.contains(COMPANION_CLASS_NAME_SUFFIX)
+ // Only generated in core lib.
|| name.contains(EMULATE_LIBRARY_CLASS_NAME_SUFFIX)
- || name.contains(DISPATCH_CLASS_NAME_SUFFIX)
|| name.contains(TYPE_WRAPPER_SUFFIX)
|| name.contains(VIVIFIED_TYPE_WRAPPER_SUFFIX)
- || name.contains(LAMBDA_CLASS_NAME_PREFIX)
- || name.contains(LAMBDA_GROUP_CLASS_NAME_PREFIX)
- || name.contains(OutlineOptions.CLASS_NAME)
- || name.contains(TwrCloseResourceRewriter.UTILITY_CLASS_NAME)
- || name.contains(NestBasedAccessDesugaring.NEST_CONSTRUCTOR_NAME)
- || name.contains(BackportedMethodRewriter.UTILITY_CLASS_NAME_PREFIX)
|| name.contains(DesugaredLibraryRetargeter.DESUGAR_LIB_RETARGET_CLASS_NAME_PREFIX)
- || name.contains(ServiceLoaderRewriter.SERVICE_LOADER_CLASS_NAME)
- || oldSynthesizedName(name);
+ // Non-hygienic types.
+ || isSynthesizedTypeThatCouldBeDuplicated(name);
+ }
+
+ public boolean isLegacySynthesizedTypeAllowedDuplication() {
+ String name = toSourceString();
+ return isSynthesizedTypeThatCouldBeDuplicated(name) || oldSynthesizedName(name);
+ }
+
+ 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.
+ || 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.
+ || name.contains(OutlineOptions.CLASS_NAME) // Global singleton.
+ || name.contains(TwrCloseResourceRewriter.UTILITY_CLASS_NAME) // Global singleton.
+ || name.contains(NestBasedAccessDesugaring.NEST_CONSTRUCTOR_NAME) // Global singleton.
+ || name.contains(BackportedMethodRewriter.UTILITY_CLASS_NAME_PREFIX) // Shared on reference.
+ || name.contains(ServiceLoaderRewriter.SERVICE_LOADER_CLASS_NAME); // Global singleton.
}
private boolean oldSynthesizedName(String name) {
diff --git a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
index fe85d28..3295733 100644
--- a/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/DirectMappedDexApplication.java
@@ -13,7 +13,6 @@
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import java.util.Collection;
import java.util.Collections;
import java.util.IdentityHashMap;
@@ -40,14 +39,12 @@
ImmutableList<DexClasspathClass> classpathClasses,
ImmutableList<DexLibraryClass> libraryClasses,
ImmutableList<DataResourceProvider> dataResourceProviders,
- ImmutableSet<DexType> mainDexList,
InternalOptions options,
DexString highestSortingString,
Timing timing) {
super(
proguardMap,
dataResourceProviders,
- mainDexList,
options,
highestSortingString,
timing);
@@ -74,22 +71,6 @@
return classpathClasses;
}
- public DexDefinitionSupplier getDefinitionsSupplier(
- SyntheticDefinitionsProvider syntheticDefinitionsProvider) {
- DirectMappedDexApplication self = this;
- return new DexDefinitionSupplier() {
- @Override
- public DexClass definitionFor(DexType type) {
- return syntheticDefinitionsProvider.definitionFor(type, self::definitionFor);
- }
-
- @Override
- public DexItemFactory dexItemFactory() {
- return self.dexItemFactory;
- }
- };
- }
-
@Override
public DexClass definitionFor(DexType type) {
assert type.isClassType() : "Cannot lookup definition for type: " + type;
@@ -256,7 +237,6 @@
classpathClasses,
libraryClasses,
ImmutableList.copyOf(dataResourceProviders),
- ImmutableSet.copyOf(mainDexList),
options,
highestSortingString,
timing);
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
index 35917f5..19ac497 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfo.java
@@ -22,6 +22,8 @@
ProgramMethod getUniqueReadContext();
+ boolean hasKnownWriteContexts();
+
void forEachIndirectAccess(Consumer<DexField> consumer);
void forEachIndirectAccessWithContexts(BiConsumer<DexField, ProgramMethodSet> consumer);
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollection.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollection.java
index 9d19406..b3f9c25 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollection.java
@@ -10,6 +10,8 @@
/** Provides immutable access to {@link FieldAccessInfoCollectionImpl}. */
public interface FieldAccessInfoCollection<T extends FieldAccessInfo> {
+ void destroyAccessContexts();
+
void flattenAccessContexts();
boolean contains(DexField field);
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
index 6224914..c82fcf0 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoCollectionImpl.java
@@ -16,6 +16,11 @@
private Map<DexField, FieldAccessInfoImpl> infos = new IdentityHashMap<>();
@Override
+ public void destroyAccessContexts() {
+ infos.values().forEach(FieldAccessInfoImpl::destroyAccessContexts);
+ }
+
+ @Override
public void flattenAccessContexts() {
infos.values().forEach(FieldAccessInfoImpl::flattenAccessContexts);
}
diff --git a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
index ae8a212..023e423 100644
--- a/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/FieldAccessInfoImpl.java
@@ -5,6 +5,7 @@
package com.android.tools.r8.graph;
import com.android.tools.r8.errors.Unreachable;
+import com.android.tools.r8.graph.AbstractAccessContexts.ConcreteAccessContexts;
import com.android.tools.r8.utils.collections.ProgramMethodSet;
import com.google.common.collect.Sets;
import java.util.IdentityHashMap;
@@ -36,37 +37,28 @@
// Maps every direct and indirect reference in a read-context to the set of methods in which that
// reference appears.
- private Map<DexField, ProgramMethodSet> readsWithContexts;
+ private AbstractAccessContexts readsWithContexts = AbstractAccessContexts.empty();
// Maps every direct and indirect reference in a write-context to the set of methods in which that
// reference appears.
- private Map<DexField, ProgramMethodSet> writesWithContexts;
+ private AbstractAccessContexts writesWithContexts = AbstractAccessContexts.empty();
public FieldAccessInfoImpl(DexField field) {
this.field = field;
}
+ void destroyAccessContexts() {
+ readsWithContexts = AbstractAccessContexts.unknown();
+ writesWithContexts = AbstractAccessContexts.unknown();
+ }
+
void flattenAccessContexts() {
flattenAccessContexts(readsWithContexts);
flattenAccessContexts(writesWithContexts);
}
- private void flattenAccessContexts(Map<DexField, ProgramMethodSet> accessesWithContexts) {
- if (accessesWithContexts != null) {
- ProgramMethodSet flattenedAccessContexts =
- accessesWithContexts.computeIfAbsent(field, ignore -> ProgramMethodSet.create());
- accessesWithContexts.forEach(
- (access, contexts) -> {
- if (access != field) {
- flattenedAccessContexts.addAll(contexts);
- }
- });
- accessesWithContexts.clear();
- if (!flattenedAccessContexts.isEmpty()) {
- accessesWithContexts.put(field, flattenedAccessContexts);
- }
- assert accessesWithContexts.size() <= 1;
- }
+ private void flattenAccessContexts(AbstractAccessContexts accessesWithContexts) {
+ accessesWithContexts.flattenAccessContexts(field);
}
@Override
@@ -81,33 +73,24 @@
@Override
public int getNumberOfReadContexts() {
- return getNumberOfAccessContexts(readsWithContexts);
+ return readsWithContexts.getNumberOfAccessContexts();
}
@Override
public int getNumberOfWriteContexts() {
- return getNumberOfAccessContexts(writesWithContexts);
- }
-
- private int getNumberOfAccessContexts(Map<DexField, ProgramMethodSet> accessesWithContexts) {
- if (accessesWithContexts == null) {
- return 0;
- }
- if (accessesWithContexts.size() == 1) {
- return accessesWithContexts.values().iterator().next().size();
- }
- throw new Unreachable("Should only be querying the number of access contexts after flattening");
+ return writesWithContexts.getNumberOfAccessContexts();
}
@Override
public ProgramMethod getUniqueReadContext() {
- if (readsWithContexts != null && readsWithContexts.size() == 1) {
- ProgramMethodSet contexts = readsWithContexts.values().iterator().next();
- if (contexts.size() == 1) {
- return contexts.iterator().next();
- }
- }
- return null;
+ return readsWithContexts.isConcrete()
+ ? readsWithContexts.asConcrete().getUniqueAccessContext()
+ : null;
+ }
+
+ @Override
+ public boolean hasKnownWriteContexts() {
+ return !writesWithContexts.isTop();
}
@Override
@@ -115,76 +98,71 @@
// There can be indirect reads and writes of the same field reference, so we need to keep track
// of the previously-seen indirect accesses to avoid reporting duplicates.
Set<DexField> visited = Sets.newIdentityHashSet();
- forEachAccessInMap(
- readsWithContexts, access -> access != field && visited.add(access), consumer);
- forEachAccessInMap(
- writesWithContexts, access -> access != field && visited.add(access), consumer);
+ forEachIndirectAccess(consumer, readsWithContexts, visited);
+ forEachIndirectAccess(consumer, writesWithContexts, visited);
}
- private static void forEachAccessInMap(
- Map<DexField, ProgramMethodSet> accessesWithContexts,
- Predicate<DexField> predicate,
- Consumer<DexField> consumer) {
- if (accessesWithContexts != null) {
- accessesWithContexts.forEach(
- (access, contexts) -> {
- if (predicate.test(access)) {
- consumer.accept(access);
- }
- });
+ private void forEachIndirectAccess(
+ Consumer<DexField> consumer,
+ AbstractAccessContexts accessesWithContexts,
+ Set<DexField> visited) {
+ if (accessesWithContexts.isBottom()) {
+ return;
}
+ if (accessesWithContexts.isConcrete()) {
+ accessesWithContexts
+ .asConcrete()
+ .forEachAccess(consumer, access -> access != field && visited.add(access));
+ return;
+ }
+ throw new Unreachable("Should never be iterating the indirect accesses when they are unknown");
}
@Override
public void forEachIndirectAccessWithContexts(BiConsumer<DexField, ProgramMethodSet> consumer) {
Map<DexField, ProgramMethodSet> indirectAccessesWithContexts = new IdentityHashMap<>();
- extendAccessesWithContexts(
- indirectAccessesWithContexts, access -> access != field, readsWithContexts);
- extendAccessesWithContexts(
- indirectAccessesWithContexts, access -> access != field, writesWithContexts);
+ addAccessesWithContextsToMap(
+ readsWithContexts, access -> access != field, indirectAccessesWithContexts);
+ addAccessesWithContextsToMap(
+ writesWithContexts, access -> access != field, indirectAccessesWithContexts);
indirectAccessesWithContexts.forEach(consumer);
}
- private void extendAccessesWithContexts(
+ private static void addAccessesWithContextsToMap(
+ AbstractAccessContexts accessesWithContexts,
+ Predicate<DexField> predicate,
+ Map<DexField, ProgramMethodSet> out) {
+ if (accessesWithContexts.isBottom()) {
+ return;
+ }
+ if (accessesWithContexts.isConcrete()) {
+ extendAccessesWithContexts(
+ accessesWithContexts.asConcrete().getAccessesWithContexts(), predicate, out);
+ return;
+ }
+ throw new Unreachable("Should never be iterating the indirect accesses when they are unknown");
+ }
+
+ private static void extendAccessesWithContexts(
Map<DexField, ProgramMethodSet> accessesWithContexts,
Predicate<DexField> predicate,
- Map<DexField, ProgramMethodSet> extension) {
- if (extension != null) {
- extension.forEach(
- (access, contexts) -> {
- if (predicate.test(access)) {
- accessesWithContexts
- .computeIfAbsent(access, ignore -> ProgramMethodSet.create())
- .addAll(contexts);
- }
- });
- }
+ Map<DexField, ProgramMethodSet> out) {
+ accessesWithContexts.forEach(
+ (access, contexts) -> {
+ if (predicate.test(access)) {
+ out.computeIfAbsent(access, ignore -> ProgramMethodSet.create()).addAll(contexts);
+ }
+ });
}
@Override
public void forEachReadContext(Consumer<ProgramMethod> consumer) {
- forEachAccessContext(readsWithContexts, consumer);
+ readsWithContexts.forEachAccessContext(consumer);
}
@Override
public void forEachWriteContext(Consumer<ProgramMethod> consumer) {
- forEachAccessContext(writesWithContexts, consumer);
- }
-
- private void forEachAccessContext(
- Map<DexField, ProgramMethodSet> accessesWithContexts, Consumer<ProgramMethod> consumer) {
- // There can be indirect reads and writes of the same field reference, so we need to keep track
- // of the previously-seen indirect accesses to avoid reporting duplicates.
- ProgramMethodSet visited = ProgramMethodSet.create();
- if (accessesWithContexts != null) {
- for (ProgramMethodSet encodedAccessContexts : accessesWithContexts.values()) {
- for (ProgramMethod encodedAccessContext : encodedAccessContexts) {
- if (visited.add(encodedAccessContext)) {
- consumer.accept(encodedAccessContext);
- }
- }
- }
- }
+ writesWithContexts.forEachAccessContext(consumer);
}
@Override
@@ -199,7 +177,7 @@
/** Returns true if this field is read by the program. */
@Override
public boolean isRead() {
- return (readsWithContexts != null && !readsWithContexts.isEmpty()) || isReadFromAnnotation();
+ return !readsWithContexts.isEmpty() || isReadFromAnnotation();
}
@Override
@@ -223,7 +201,7 @@
/** Returns true if this field is written by the program. */
@Override
public boolean isWritten() {
- return writesWithContexts != null && !writesWithContexts.isEmpty();
+ return !writesWithContexts.isEmpty();
}
@Override
@@ -240,16 +218,7 @@
*/
@Override
public boolean isWrittenInMethodSatisfying(Predicate<ProgramMethod> predicate) {
- if (writesWithContexts != null) {
- for (ProgramMethodSet encodedWriteContexts : writesWithContexts.values()) {
- for (ProgramMethod encodedWriteContext : encodedWriteContexts) {
- if (predicate.test(encodedWriteContext)) {
- return true;
- }
- }
- }
- }
- return false;
+ return writesWithContexts.isAccessedInMethodSatisfying(predicate);
}
/**
@@ -258,16 +227,7 @@
*/
@Override
public boolean isWrittenOnlyInMethodSatisfying(Predicate<ProgramMethod> predicate) {
- if (writesWithContexts != null) {
- for (ProgramMethodSet encodedWriteContexts : writesWithContexts.values()) {
- for (ProgramMethod encodedWriteContext : encodedWriteContexts) {
- if (!predicate.test(encodedWriteContext)) {
- return false;
- }
- }
- }
- }
- return true;
+ return writesWithContexts.isAccessedOnlyInMethodSatisfying(predicate);
}
/**
@@ -275,71 +235,42 @@
*/
@Override
public boolean isWrittenOutside(DexEncodedMethod method) {
- if (writesWithContexts != null) {
- for (ProgramMethodSet encodedWriteContexts : writesWithContexts.values()) {
- for (ProgramMethod encodedWriteContext : encodedWriteContexts) {
- if (encodedWriteContext.getDefinition() != method) {
- return true;
- }
- }
- }
+ return writesWithContexts.isAccessedOutside(method);
+ }
+
+ public boolean recordRead(DexField access, ProgramMethod context) {
+ if (readsWithContexts.isBottom()) {
+ readsWithContexts = new ConcreteAccessContexts();
+ }
+ if (readsWithContexts.isConcrete()) {
+ return readsWithContexts.asConcrete().recordAccess(access, context);
}
return false;
}
- public boolean recordRead(DexField access, ProgramMethod context) {
- if (readsWithContexts == null) {
- readsWithContexts = new IdentityHashMap<>();
- }
- return readsWithContexts
- .computeIfAbsent(access, ignore -> ProgramMethodSet.create())
- .add(context);
- }
-
public boolean recordWrite(DexField access, ProgramMethod context) {
- if (writesWithContexts == null) {
- writesWithContexts = new IdentityHashMap<>();
+ if (writesWithContexts.isBottom()) {
+ writesWithContexts = new ConcreteAccessContexts();
}
- return writesWithContexts
- .computeIfAbsent(access, ignore -> ProgramMethodSet.create())
- .add(context);
+ if (writesWithContexts.isConcrete()) {
+ return writesWithContexts.asConcrete().recordAccess(access, context);
+ }
+ return false;
}
public void clearReads() {
- readsWithContexts = null;
+ readsWithContexts = AbstractAccessContexts.empty();
}
public void clearWrites() {
- writesWithContexts = null;
+ writesWithContexts = AbstractAccessContexts.empty();
}
public FieldAccessInfoImpl rewrittenWithLens(DexDefinitionSupplier definitions, GraphLens lens) {
FieldAccessInfoImpl rewritten = new FieldAccessInfoImpl(lens.lookupField(field));
rewritten.flags = flags;
- if (readsWithContexts != null) {
- rewritten.readsWithContexts = new IdentityHashMap<>();
- readsWithContexts.forEach(
- (access, contexts) -> {
- ProgramMethodSet newContexts =
- rewritten.readsWithContexts.computeIfAbsent(
- lens.lookupField(access), ignore -> ProgramMethodSet.create());
- for (ProgramMethod context : contexts) {
- newContexts.add(lens.mapProgramMethod(context, definitions));
- }
- });
- }
- if (writesWithContexts != null) {
- rewritten.writesWithContexts = new IdentityHashMap<>();
- writesWithContexts.forEach(
- (access, contexts) -> {
- ProgramMethodSet newContexts =
- rewritten.writesWithContexts.computeIfAbsent(
- lens.lookupField(access), ignore -> ProgramMethodSet.create());
- for (ProgramMethod context : contexts) {
- newContexts.add(lens.mapProgramMethod(context, definitions));
- }
- });
- }
+ rewritten.readsWithContexts = readsWithContexts.rewrittenWithLens(definitions, lens);
+ rewritten.writesWithContexts = writesWithContexts.rewrittenWithLens(definitions, lens);
return rewritten;
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/GraphLens.java b/src/main/java/com/android/tools/r8/graph/GraphLens.java
index 2491193..14a4e95 100644
--- a/src/main/java/com/android/tools/r8/graph/GraphLens.java
+++ b/src/main/java/com/android/tools/r8/graph/GraphLens.java
@@ -3,6 +3,7 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.horizontalclassmerging.ClassMerger;
import com.android.tools.r8.ir.code.Invoke.Type;
import com.android.tools.r8.ir.desugar.InterfaceProcessor.InterfaceProcessorNestedGraphLens;
import com.android.tools.r8.shaking.KeepInfoCollection;
@@ -408,6 +409,12 @@
if (field.field.match(dexItemFactory.objectMembers.clinitField)) {
continue;
}
+
+ // TODO(b/167947782): Should be a general check to see if the field is D8/R8 synthesized.
+ if (field.toReference().name.toSourceString().equals(ClassMerger.CLASS_ID_FIELD_NAME)) {
+ continue;
+ }
+
DexField originalField = getOriginalFieldSignature(field.field);
assert originalFields.contains(originalField)
: "Unable to map field `" + field.field.toSourceString() + "` back to original program";
diff --git a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
index 1721860..ce5ff83 100644
--- a/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
+++ b/src/main/java/com/android/tools/r8/graph/LazyLoadedDexApplication.java
@@ -15,7 +15,6 @@
import com.android.tools.r8.utils.ProgramClassCollection;
import com.android.tools.r8.utils.Timing;
import com.google.common.collect.ImmutableList;
-import com.google.common.collect.ImmutableSet;
import java.util.Collections;
import java.util.IdentityHashMap;
import java.util.List;
@@ -34,14 +33,12 @@
ImmutableList<DataResourceProvider> dataResourceProviders,
ClasspathClassCollection classpathClasses,
LibraryClassCollection libraryClasses,
- ImmutableSet<DexType> mainDexList,
InternalOptions options,
DexString highestSortingString,
Timing timing) {
super(
proguardMap,
dataResourceProviders,
- mainDexList,
options,
highestSortingString,
timing);
@@ -236,7 +233,6 @@
ImmutableList.copyOf(dataResourceProviders),
classpathClasses,
libraryClasses,
- ImmutableSet.copyOf(mainDexList),
options,
highestSortingString,
timing);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
index c7edad2..949fd47 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodArrayBacking.java
@@ -269,12 +269,28 @@
@Override
public DexEncodedMethod replaceDirectMethod(
DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) {
- for (int i = 0; i < directMethods.length; i++) {
- DexEncodedMethod directMethod = directMethods[i];
- if (method.match(directMethod)) {
- DexEncodedMethod newMethod = replacement.apply(directMethod);
- assert belongsToDirectPool(newMethod);
- directMethods[i] = newMethod;
+ DexEncodedMethod newMethod = replaceMethod(method, replacement, directMethods);
+ assert newMethod == null || belongsToDirectPool(newMethod);
+ return newMethod;
+ }
+
+ @Override
+ public DexEncodedMethod replaceVirtualMethod(
+ DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) {
+ DexEncodedMethod newMethod = replaceMethod(method, replacement, virtualMethods);
+ assert newMethod == null || belongsToVirtualPool(newMethod);
+ return newMethod;
+ }
+
+ private DexEncodedMethod replaceMethod(
+ DexMethod reference,
+ Function<DexEncodedMethod, DexEncodedMethod> replacement,
+ DexEncodedMethod[] methods) {
+ for (int i = 0; i < methods.length; i++) {
+ DexEncodedMethod method = methods[i];
+ if (reference.match(method)) {
+ DexEncodedMethod newMethod = replacement.apply(method);
+ methods[i] = newMethod;
return newMethod;
}
}
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollection.java b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
index b1a8f8e..312cec2 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollection.java
@@ -212,6 +212,12 @@
return backing.replaceDirectMethod(method, replacement);
}
+ public DexEncodedMethod replaceVirtualMethod(
+ DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) {
+ resetVirtualMethodCaches();
+ return backing.replaceVirtualMethod(method, replacement);
+ }
+
public void replaceMethods(Function<DexEncodedMethod, DexEncodedMethod> replacement) {
resetCaches();
backing.replaceMethods(replacement);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java b/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
index 0b3f435..601306c 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodCollectionBacking.java
@@ -113,6 +113,9 @@
abstract DexEncodedMethod replaceDirectMethod(
DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement);
+ abstract DexEncodedMethod replaceVirtualMethod(
+ DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement);
+
abstract DexEncodedMethod replaceDirectMethodWithVirtualMethod(
DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement);
diff --git a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
index 19c3cec..d95a723 100644
--- a/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
+++ b/src/main/java/com/android/tools/r8/graph/MethodMapBacking.java
@@ -286,13 +286,26 @@
@Override
DexEncodedMethod replaceDirectMethod(
DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) {
+ return replaceMethod(method, replacement, this::belongsToDirectPool);
+ }
+
+ @Override
+ DexEncodedMethod replaceVirtualMethod(
+ DexMethod method, Function<DexEncodedMethod, DexEncodedMethod> replacement) {
+ return replaceMethod(method, replacement, this::belongsToVirtualPool);
+ }
+
+ private DexEncodedMethod replaceMethod(
+ DexMethod method,
+ Function<DexEncodedMethod, DexEncodedMethod> replacement,
+ Predicate<DexEncodedMethod> predicate) {
Wrapper<DexMethod> key = wrap(method);
DexEncodedMethod existing = methodMap.get(key);
- if (existing == null || belongsToVirtualPool(existing)) {
+ if (existing == null || !predicate.test(existing)) {
return null;
}
DexEncodedMethod newMethod = replacement.apply(existing);
- assert belongsToDirectPool(newMethod);
+ assert predicate.test(newMethod);
replace(key, newMethod);
return newMethod;
}
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java
index 60c06cc..28ab2ca 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollection.java
@@ -16,6 +16,8 @@
void forEachClassWithKnownAllocationSites(
BiConsumer<DexProgramClass, Set<DexEncodedMethod>> consumer);
+ boolean hasInstantiatedStrictSubtype(DexProgramClass clazz);
+
boolean isAllocationSitesKnown(DexProgramClass clazz);
boolean isInstantiatedDirectly(DexProgramClass clazz);
diff --git a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
index fb6e5d1..fa105e6 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectAllocationInfoCollectionImpl.java
@@ -93,6 +93,7 @@
}
/** True if there might exist an instantiated (strict) subtype of the given type. */
+ @Override
public boolean hasInstantiatedStrictSubtype(DexProgramClass clazz) {
if (instantiatedHierarchy.get(clazz.type) != null) {
return true;
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 33f3b90..ecc7505 100644
--- a/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
+++ b/src/main/java/com/android/tools/r8/graph/ObjectToOffsetMapping.java
@@ -5,6 +5,7 @@
import com.android.tools.r8.dex.Constants;
import com.android.tools.r8.errors.CompilationError;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.NamingLens;
import it.unimi.dsi.fastutil.objects.Reference2IntLinkedOpenHashMap;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
@@ -23,8 +24,10 @@
private final static int NOT_FOUND = -1;
private final static int NOT_SET = -2;
+ private final GraphLens graphLens;
private final NamingLens namingLens;
private final InitClassLens initClassLens;
+ private final LensCodeRewriterUtils lensCodeRewriter;
// Sorted collection of objects mapped to their offsets.
private final DexProgramClass[] classes;
@@ -39,7 +42,8 @@
private DexString firstJumboString;
public ObjectToOffsetMapping(
- DexApplication application,
+ AppInfo appInfo,
+ GraphLens graphLens,
NamingLens namingLens,
InitClassLens initClassLens,
Collection<DexProgramClass> classes,
@@ -50,7 +54,7 @@
Collection<DexString> strings,
Collection<DexCallSite> callSites,
Collection<DexMethodHandle> methodHandles) {
- assert application != null;
+ assert appInfo != null;
assert classes != null;
assert protos != null;
assert types != null;
@@ -60,9 +64,11 @@
assert callSites != null;
assert methodHandles != null;
assert initClassLens != null;
+ this.graphLens = graphLens;
this.namingLens = namingLens;
this.initClassLens = initClassLens;
- this.classes = sortClasses(application, classes, namingLens);
+ this.lensCodeRewriter = new LensCodeRewriterUtils(appInfo, graphLens);
+ this.classes = sortClasses(appInfo, classes, namingLens);
this.protos = createSortedMap(protos, compare(namingLens), this::failOnOverflow);
this.types = createSortedMap(types, compare(namingLens), this::failOnOverflow);
this.methods = createSortedMap(methods, compare(namingLens), this::failOnOverflow);
@@ -114,11 +120,11 @@
private final static int UNKNOWN_DEPTH = -1;
- private final DexApplication application;
+ private final AppInfo appInfo;
private final Reference2IntMap<DexProgramClass> depthOfClasses = new Reference2IntOpenHashMap<>();
- ProgramClassDepthsMemoized(DexApplication application) {
- this.application = application;
+ ProgramClassDepthsMemoized(AppInfo appInfo) {
+ this.appInfo = appInfo;
depthOfClasses.defaultReturnValue(UNKNOWN_DEPTH);
}
@@ -134,13 +140,13 @@
maxDepth = 0;
} else {
maxDepth = 1;
- DexProgramClass superClass = application.programDefinitionFor(superType);
+ DexProgramClass superClass = appInfo.programDefinitionFor(superType, programClass);
if (superClass != null) {
maxDepth = getDepth(superClass);
}
}
for (DexType inf : programClass.interfaces.values) {
- DexProgramClass infClass = application.programDefinitionFor(inf);
+ DexProgramClass infClass = appInfo.programDefinitionFor(inf, programClass);
maxDepth = Math.max(maxDepth, infClass == null ? 1 : getDepth(infClass));
}
depth = maxDepth + 1;
@@ -152,9 +158,9 @@
}
private static DexProgramClass[] sortClasses(
- DexApplication application, Collection<DexProgramClass> classes, NamingLens namingLens) {
+ AppInfo appInfo, Collection<DexProgramClass> classes, NamingLens namingLens) {
// Collect classes in subtyping order, based on a sorted list of classes to start with.
- ProgramClassDepthsMemoized classDepths = new ProgramClassDepthsMemoized(application);
+ ProgramClassDepthsMemoized classDepths = new ProgramClassDepthsMemoized(appInfo);
List<DexProgramClass> sortedClasses =
classes.stream()
.sorted(
@@ -172,10 +178,18 @@
return map == null ? Collections.emptyList() : map.keySet();
}
+ public GraphLens getGraphLens() {
+ return graphLens;
+ }
+
public NamingLens getNamingLens() {
return namingLens;
}
+ public LensCodeRewriterUtils getLensCodeRewriter() {
+ return lensCodeRewriter;
+ }
+
public Collection<DexMethod> getMethods() {
return keysOrEmpty(methods);
}
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramDexCode.java b/src/main/java/com/android/tools/r8/graph/ProgramDexCode.java
new file mode 100644
index 0000000..93e42d1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/graph/ProgramDexCode.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.graph;
+
+public class ProgramDexCode {
+
+ private final DexCode code;
+ private final ProgramMethod method;
+
+ public ProgramDexCode(DexCode code, ProgramMethod method) {
+ this.code = code;
+ this.method = method;
+ }
+
+ public DexCode getCode() {
+ return code;
+ }
+
+ public ProgramMethod getMethod() {
+ return method;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramField.java b/src/main/java/com/android/tools/r8/graph/ProgramField.java
index 3069f4e..7721c67 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramField.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramField.java
@@ -4,6 +4,8 @@
package com.android.tools.r8.graph;
+import com.android.tools.r8.dex.IndexedItemCollection;
+
public class ProgramField extends DexClassAndField
implements ProgramMember<DexEncodedField, DexField> {
@@ -11,6 +13,15 @@
super(holder, field);
}
+ public void collectIndexedItems(IndexedItemCollection indexedItems) {
+ getReference().collectIndexedItems(indexedItems);
+ DexEncodedField definition = getDefinition();
+ definition.annotations().collectIndexedItems(indexedItems);
+ if (definition.isStatic() && definition.hasExplicitStaticValue()) {
+ definition.getStaticValue().collectIndexedItems(indexedItems);
+ }
+ }
+
public boolean isStructurallyEqualTo(ProgramField other) {
return getDefinition() == other.getDefinition() && getHolder() == other.getHolder();
}
diff --git a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
index e69ade7..a1fe5c7 100644
--- a/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
+++ b/src/main/java/com/android/tools/r8/graph/ProgramMethod.java
@@ -3,9 +3,11 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.graph;
+import com.android.tools.r8.dex.IndexedItemCollection;
import com.android.tools.r8.ir.code.IRCode;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.ir.conversion.MethodProcessor;
import com.android.tools.r8.logging.Log;
import com.android.tools.r8.origin.Origin;
@@ -35,6 +37,20 @@
context, this, appView, valueNumberGenerator, callerPosition, origin, methodProcessor);
}
+ public void collectIndexedItems(
+ IndexedItemCollection indexedItems, GraphLens graphLens, LensCodeRewriterUtils rewriter) {
+ DexEncodedMethod definition = getDefinition();
+ assert !definition.isObsolete();
+ assert !definition.hasCode() || definition.getCode().isDexCode();
+ getReference().collectIndexedItems(indexedItems);
+ Code code = definition.getCode();
+ if (code != null && code.isDexCode()) {
+ code.asDexCode().collectIndexedItems(indexedItems, this, graphLens, rewriter);
+ }
+ definition.annotations().collectIndexedItems(indexedItems);
+ definition.parameterAnnotationsList.collectIndexedItems(indexedItems);
+ }
+
public boolean isStructurallyEqualTo(ProgramMethod other) {
return getDefinition() == other.getDefinition() && getHolder() == other.getHolder();
}
diff --git a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
index 3316b64..82b02c4 100644
--- a/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
+++ b/src/main/java/com/android/tools/r8/graph/ResolutionResult.java
@@ -177,6 +177,12 @@
return resolvedMethod;
}
+ public ProgramMethod getResolvedProgramMethod() {
+ return resolvedHolder.isProgramClass()
+ ? new ProgramMethod(resolvedHolder.asProgramClass(), resolvedMethod)
+ : null;
+ }
+
public DexClassAndMethod getResolutionPair() {
return DexClassAndMethod.create(resolvedHolder, resolvedMethod);
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
index 51ef31e..1f751ad 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ClassMerger.java
@@ -17,13 +17,16 @@
import com.android.tools.r8.graph.DexType;
import com.android.tools.r8.graph.FieldAccessFlags;
import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
import com.android.tools.r8.utils.MethodSignatureEquivalence;
import com.google.common.base.Equivalence.Wrapper;
import it.unimi.dsi.fastutil.objects.Reference2IntMap;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.IdentityHashMap;
+import java.util.LinkedHashMap;
import java.util.Map;
/**
@@ -31,8 +34,10 @@
* class {@link ClassMerger#target}. While performing merging, this class tracks which methods have
* been moved, as well as which fields have been remapped in the {@link ClassMerger#lensBuilder}.
*/
-class ClassMerger {
- private final AppView<?> appView;
+public class ClassMerger {
+ public static final String CLASS_ID_FIELD_NAME = "$r8$classId";
+
+ private final AppView<AppInfoWithLiveness> appView;
private final DexProgramClass target;
private final Collection<DexProgramClass> toMergeGroup;
private final DexItemFactory dexItemFactory;
@@ -40,41 +45,33 @@
private final FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder;
private final Reference2IntMap<DexType> classIdentifiers = new Reference2IntOpenHashMap<>();
- private final Map<DexProto, ConstructorMerger.Builder> constructorMergers;
+ private final Collection<VirtualMethodMerger> virtualMethodMergers;
+ private final Collection<ConstructorMerger> constructorMergers;
private final DexField classIdField;
- ClassMerger(
- AppView<?> appView,
+ private ClassMerger(
+ AppView<AppInfoWithLiveness> appView,
HorizontalClassMergerGraphLens.Builder lensBuilder,
FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder,
DexProgramClass target,
- Collection<DexProgramClass> toMergeGroup) {
+ Collection<DexProgramClass> toMergeGroup,
+ DexField classIdField,
+ Collection<VirtualMethodMerger> virtualMethodMergers,
+ Collection<ConstructorMerger> constructorMergers) {
this.appView = appView;
this.lensBuilder = lensBuilder;
this.fieldAccessChangesBuilder = fieldAccessChangesBuilder;
this.target = target;
this.toMergeGroup = toMergeGroup;
+ this.classIdField = classIdField;
+ this.virtualMethodMergers = virtualMethodMergers;
+ this.constructorMergers = constructorMergers;
- this.constructorMergers = new IdentityHashMap<>();
this.dexItemFactory = appView.dexItemFactory();
- // TODO(b/165498187): ensure the name for the field is fresh
- classIdField = dexItemFactory.createField(target.type, dexItemFactory.intType, "$r8$classId");
-
buildClassIdentifierMap();
}
- Wrapper<DexMethod> bySignature(DexMethod method) {
- return MethodSignatureEquivalence.get().wrap(method);
- }
-
- void addConstructor(DexEncodedMethod method) {
- assert method.isInstanceInitializer();
- constructorMergers
- .computeIfAbsent(method.proto(), ignore -> new ConstructorMerger.Builder())
- .add(method);
- }
-
void buildClassIdentifierMap() {
classIdentifiers.put(target.type, 0);
for (DexProgramClass toMerge : toMergeGroup) {
@@ -83,21 +80,16 @@
}
void merge(DexProgramClass toMerge) {
- toMerge.forEachProgramMethod(
- programMethod -> {
- DexEncodedMethod method = programMethod.getDefinition();
- assert !method.isClassInitializer();
+ toMerge.forEachProgramDirectMethod(
+ method -> {
+ DexEncodedMethod definition = method.getDefinition();
+ assert !definition.isClassInitializer();
- if (method.isInstanceInitializer()) {
- addConstructor(method);
- } else {
- // TODO(b/166427795): Ensure that overriding relationships are not changed.
- assert method.isVirtualMethod();
-
- DexMethod newMethod = renameMethod(programMethod);
- // TODO(b/165000217): Add all methods to `target` in one go using addVirtualMethods().;
- target.addVirtualMethod(method.toTypeSubstitutedMethod(newMethod));
- lensBuilder.moveMethod(method.method, newMethod);
+ if (!definition.isInstanceInitializer()) {
+ DexMethod newMethod = renameMethod(method);
+ // TODO(b/165000217): Add all methods to `target` in one go using addDirectMethods().
+ target.addDirectMethod(definition.toTypeSubstitutedMethod(newMethod));
+ lensBuilder.moveMethod(definition.getReference(), newMethod);
}
});
@@ -123,24 +115,15 @@
}
void mergeConstructors() {
- for (ConstructorMerger.Builder builder : constructorMergers.values()) {
- ConstructorMerger constructorMerger = builder.build(appView, target, classIdField);
- constructorMerger.merge(lensBuilder, fieldAccessChangesBuilder, classIdentifiers);
+ for (ConstructorMerger merger : constructorMergers) {
+ merger.merge(lensBuilder, fieldAccessChangesBuilder, classIdentifiers);
}
}
- /**
- * To ensure constructor merging happens correctly, add all of the target constructors methods to
- * constructor mergers.
- */
- void addTargetConstructors() {
- target.forEachProgramDirectMethod(
- programMethod -> {
- DexEncodedMethod method = programMethod.getDefinition();
- if (method.isInstanceInitializer()) {
- addConstructor(method);
- }
- });
+ void mergeVirtualMethods() {
+ for (VirtualMethodMerger merger : virtualMethodMergers) {
+ merger.merge(lensBuilder, fieldAccessChangesBuilder, classIdentifiers);
+ }
}
void appendClassIdField() {
@@ -155,13 +138,102 @@
}
public void mergeGroup() {
- addTargetConstructors();
appendClassIdField();
for (DexProgramClass clazz : toMergeGroup) {
merge(clazz);
+ lensBuilder.mapType(clazz.type, target.type);
}
mergeConstructors();
+ mergeVirtualMethods();
+ }
+
+ public static class Builder {
+ private final DexProgramClass target;
+ private final Collection<DexProgramClass> toMergeGroup = new ArrayList<>();
+ private final Map<DexProto, ConstructorMerger.Builder> constructorMergerBuilders =
+ new IdentityHashMap<>();
+ private final Map<Wrapper<DexMethod>, VirtualMethodMerger.Builder> virtualMethodMergerBuilders =
+ new LinkedHashMap<>();
+
+ public Builder(DexProgramClass target) {
+ this.target = target;
+ setupForMethodMerging(target);
+ }
+
+ public Builder mergeClass(DexProgramClass toMerge) {
+ setupForMethodMerging(toMerge);
+ toMergeGroup.add(toMerge);
+ return this;
+ }
+
+ public Builder addClassesToMerge(Collection<DexProgramClass> toMerge) {
+ toMerge.forEach(this::mergeClass);
+ return this;
+ }
+
+ void setupForMethodMerging(DexProgramClass toMerge) {
+ toMerge.forEachProgramDirectMethod(
+ method -> {
+ DexEncodedMethod definition = method.getDefinition();
+ assert !definition.isClassInitializer();
+
+ if (definition.isInstanceInitializer()) {
+ addConstructor(method);
+ }
+ });
+
+ toMerge.forEachProgramVirtualMethod(this::addVirtualMethod);
+ }
+
+ void addConstructor(ProgramMethod method) {
+ assert method.getDefinition().isInstanceInitializer();
+ constructorMergerBuilders
+ .computeIfAbsent(
+ method.getDefinition().getProto(), ignore -> new ConstructorMerger.Builder())
+ .add(method.getDefinition());
+ }
+
+ void addVirtualMethod(ProgramMethod method) {
+ assert method.getDefinition().isNonPrivateVirtualMethod();
+ virtualMethodMergerBuilders
+ .computeIfAbsent(
+ MethodSignatureEquivalence.get().wrap(method.getReference()),
+ ignore -> new VirtualMethodMerger.Builder())
+ .add(method);
+ }
+
+ public ClassMerger build(
+ AppView<AppInfoWithLiveness> appView,
+ HorizontalClassMergerGraphLens.Builder lensBuilder,
+ FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder) {
+ DexItemFactory dexItemFactory = appView.dexItemFactory();
+ // TODO(b/165498187): ensure the name for the field is fresh
+ DexField classIdField =
+ dexItemFactory.createField(target.type, dexItemFactory.intType, CLASS_ID_FIELD_NAME);
+
+ Collection<VirtualMethodMerger> virtualMethodMergers =
+ new ArrayList<>(virtualMethodMergerBuilders.size());
+ for (VirtualMethodMerger.Builder builder : virtualMethodMergerBuilders.values()) {
+ virtualMethodMergers.add(builder.build(appView, target, classIdField));
+ }
+
+ Collection<ConstructorMerger> constructorMergers =
+ new ArrayList<>(constructorMergerBuilders.size());
+ for (ConstructorMerger.Builder builder : constructorMergerBuilders.values()) {
+ constructorMergers.add(builder.build(appView, target, classIdField));
+ }
+
+ return new ClassMerger(
+ appView,
+ lensBuilder,
+ fieldAccessChangesBuilder,
+ target,
+ toMergeGroup,
+ classIdField,
+ virtualMethodMergers,
+ constructorMergers);
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
index 76f4814..cd2d31c 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/ConstructorMerger.java
@@ -107,7 +107,8 @@
private MethodAccessFlags getAccessFlags() {
// TODO(b/164998929): ensure this behaviour is correct, should probably calculate upper bound
- return MethodAccessFlags.fromSharedAccessFlags(Constants.ACC_PUBLIC, true);
+ return MethodAccessFlags.fromSharedAccessFlags(
+ Constants.ACC_PUBLIC | Constants.ACC_SYNTHETIC, true);
}
/** Synthesize a new method which selects the constructor based on a parameter type. */
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 f7ac858..a938abb 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMerger.java
@@ -6,7 +6,6 @@
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.policies.NoFields;
import com.android.tools.r8.horizontalclassmerging.policies.NoInterfaces;
import com.android.tools.r8.horizontalclassmerging.policies.NoInternalUtilityClasses;
@@ -17,12 +16,11 @@
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.shaking.ClassMergingEnqueuerExtension;
import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
-import com.android.tools.r8.shaking.MainDexClasses;
+import com.android.tools.r8.shaking.MainDexTracingResult;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
-import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
@@ -32,7 +30,7 @@
public HorizontalClassMerger(
AppView<AppInfoWithLiveness> appView,
- MainDexClasses mainDexClasses,
+ MainDexTracingResult mainDexClasses,
ClassMergingEnqueuerExtension classMergingEnqueuerExtension) {
this.appView = appView;
@@ -52,6 +50,7 @@
this.policyExecutor = new SimplePolicyExecutor(policies);
}
+ // TODO(b/165577835): replace Collection<DexProgramClass> with MergeGroup
public HorizontalClassMergerGraphLens run() {
Map<FieldMultiset, Collection<DexProgramClass>> classes = new HashMap<>();
@@ -63,23 +62,32 @@
// Run the policies on all collected classes to produce a final grouping.
Collection<Collection<DexProgramClass>> groups = policyExecutor.run(classes.values());
- return createLens(groups);
- }
-
- // TODO(b/165577835): replace Collection<DexProgramClass> with MergeGroup
- /**
- * Merges all class groups using {@link ClassMerger}. Then fix all references to merged classes
- * using the {@link TreeFixer}. Constructs a graph lens containing all changes while performing
- * merging.
- */
- private HorizontalClassMergerGraphLens createLens(
- Collection<Collection<DexProgramClass>> groups) {
- Map<DexType, DexType> mergedClasses = new IdentityHashMap<>();
HorizontalClassMergerGraphLens.Builder lensBuilder =
new HorizontalClassMergerGraphLens.Builder();
FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder =
new FieldAccessInfoCollectionModifier.Builder();
+ // Set up a class merger for each group.
+ Collection<ClassMerger> classMergers =
+ initializeClassMergers(lensBuilder, fieldAccessChangesBuilder, groups);
+
+ // Merge the classes.
+ applyClassMergers(classMergers);
+
+ // Generate the class lens.
+ return createLens(lensBuilder, fieldAccessChangesBuilder);
+ }
+
+ /**
+ * Prepare horizontal class merging by determining which virtual methods and constructors need to
+ * be merged and how the merging should be performed.
+ */
+ private Collection<ClassMerger> initializeClassMergers(
+ HorizontalClassMergerGraphLens.Builder lensBuilder,
+ FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder,
+ Collection<Collection<DexProgramClass>> groups) {
+ Collection<ClassMerger> classMergers = new ArrayList<>();
+
// TODO(b/166577694): Replace Collection<DexProgramClass> with MergeGroup
for (Collection<DexProgramClass> group : groups) {
assert !group.isEmpty();
@@ -87,18 +95,33 @@
DexProgramClass target = group.stream().findFirst().get();
group.remove(target);
- for (DexProgramClass clazz : group) {
- mergedClasses.put(clazz.type, target.type);
- }
-
ClassMerger merger =
- new ClassMerger(appView, lensBuilder, fieldAccessChangesBuilder, target, group);
- merger.mergeGroup();
+ new ClassMerger.Builder(target)
+ .addClassesToMerge(group)
+ .build(appView, lensBuilder, fieldAccessChangesBuilder);
+ classMergers.add(merger);
}
+ return classMergers;
+ }
+
+ /** Merges all class groups using {@link ClassMerger}. */
+ private void applyClassMergers(Collection<ClassMerger> classMergers) {
+ for (ClassMerger merger : classMergers) {
+ merger.mergeGroup();
+ }
+ }
+
+ /**
+ * Fix all references to merged classes using the {@link TreeFixer}. Construct a graph lens
+ * containing all changes performed by horizontal class merging.
+ */
+ private HorizontalClassMergerGraphLens createLens(
+ HorizontalClassMergerGraphLens.Builder lensBuilder,
+ FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder) {
+
HorizontalClassMergerGraphLens lens =
- new TreeFixer(appView, lensBuilder, fieldAccessChangesBuilder, mergedClasses)
- .fixupTypeReferences();
+ new TreeFixer(appView, lensBuilder, fieldAccessChangesBuilder).fixupTypeReferences();
return lens;
}
}
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 4389282..482ade5 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/HorizontalClassMergerGraphLens.java
@@ -83,10 +83,10 @@
}
public static class Builder {
- protected final BiMap<DexField, DexField> fieldMap = HashBiMap.create();
- protected final Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>();
- protected final Map<DexMethod, Set<DexMethod>> completeInverseMethodMap =
- new IdentityHashMap<>();
+ private final Map<DexType, DexType> typeMap = new IdentityHashMap<>();
+ private final BiMap<DexField, DexField> fieldMap = HashBiMap.create();
+ private final Map<DexMethod, DexMethod> methodMap = new IdentityHashMap<>();
+ private final Map<DexMethod, Set<DexMethod>> completeInverseMethodMap = new IdentityHashMap<>();
private final BiMap<DexMethod, DexMethod> originalMethodSignatures = HashBiMap.create();
private final Map<DexMethod, DexMethod> extraOriginalMethodSignatures = new IdentityHashMap<>();
@@ -95,16 +95,15 @@
Builder() {}
- public HorizontalClassMergerGraphLens build(
- AppView<?> appView, Map<DexType, DexType> mergedClasses) {
- if (mergedClasses.isEmpty()) {
+ public HorizontalClassMergerGraphLens build(AppView<?> appView) {
+ if (typeMap.isEmpty()) {
return null;
} else {
BiMap<DexField, DexField> originalFieldSignatures = fieldMap.inverse();
return new HorizontalClassMergerGraphLens(
appView,
constructorIds,
- mergedClasses,
+ typeMap,
fieldMap,
methodMap,
originalFieldSignatures,
@@ -114,6 +113,15 @@
}
}
+ public DexType lookupType(DexType type) {
+ return typeMap.getOrDefault(type, type);
+ }
+
+ public Builder mapType(DexType from, DexType to) {
+ typeMap.put(from, to);
+ return this;
+ }
+
/** Bidirectional mapping from one method to another. */
public Builder moveMethod(DexMethod from, DexMethod to) {
mapMethod(from, to);
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 261e8d2..1ce2ee4 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/MultiClassPolicy.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/MultiClassPolicy.java
@@ -10,6 +10,13 @@
public abstract class MultiClassPolicy extends Policy {
/**
+ * 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) {
+ groups.removeIf(group -> group.size() < 2);
+ }
+
+ /**
* Apply the multi class policy to a group of program classes.
*
* @param group This is a group of program classes which can currently still be merged.
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 3e6254c..9ec4e5f 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/SimplePolicyExecutor.java
@@ -32,7 +32,7 @@
j.remove();
}
}
- if (group.isEmpty()) {
+ if (group.size() < 2) {
i.remove();
}
}
@@ -56,6 +56,9 @@
} else if (policy instanceof MultiClassPolicy) {
groups = applyMultiClassPolicy((MultiClassPolicy) policy, groups);
}
+
+ // Any policy should not return any trivial groups.
+ assert groups.stream().allMatch(group -> group.size() >= 2);
}
return groups;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
index 7d0d5c0..087c6ef 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/TreeFixer.java
@@ -23,12 +23,10 @@
/**
* The tree fixer traverses all program classes and finds and fixes references to old classes which
- * have been remapped to new classes by the class merger (stored in {@link
- * TreeFixer#mergedClasses}). While doing so, all updated changes are tracked in {@link
- * TreeFixer#lensBuilder}.
+ * have been remapped to new classes by the class merger. While doing so, all updated changes are
+ * tracked in {@link TreeFixer#lensBuilder}.
*/
class TreeFixer {
- private final Map<DexType, DexType> mergedClasses;
private final Map<DexProto, DexProto> protoFixupCache = new IdentityHashMap<>();
private final HorizontalClassMergerGraphLens.Builder lensBuilder;
private final FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder;
@@ -37,9 +35,7 @@
public TreeFixer(
AppView<AppInfoWithLiveness> appView,
HorizontalClassMergerGraphLens.Builder lensBuilder,
- FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder,
- Map<DexType, DexType> mergedClasses) {
- this.mergedClasses = mergedClasses;
+ FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder) {
this.lensBuilder = lensBuilder;
this.fieldAccessChangesBuilder = fieldAccessChangesBuilder;
this.appView = appView;
@@ -48,11 +44,12 @@
HorizontalClassMergerGraphLens fixupTypeReferences() {
// Globally substitute merged class types in protos and holders.
for (DexProgramClass clazz : appView.appInfo().classes()) {
+ clazz.superType = lensBuilder.lookupType(clazz.superType);
clazz.getMethodCollection().replaceMethods(this::fixupMethod);
fixupFields(clazz.staticFields(), clazz::setStaticField);
fixupFields(clazz.instanceFields(), clazz::setInstanceField);
}
- HorizontalClassMergerGraphLens lens = lensBuilder.build(appView, mergedClasses);
+ HorizontalClassMergerGraphLens lens = lensBuilder.build(appView);
fieldAccessChangesBuilder.build(this::fixupMethod).modify(appView);
@@ -133,8 +130,10 @@
return type.replaceBaseType(fixed, appView.dexItemFactory());
}
if (type.isClassType()) {
- while (mergedClasses.containsKey(type)) {
- type = mergedClasses.get(type);
+ while (true) {
+ DexType mapped = lensBuilder.lookupType(type);
+ if (mapped == type) break;
+ type = mapped;
}
}
return type;
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPoint.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPoint.java
new file mode 100644
index 0000000..494e383
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPoint.java
@@ -0,0 +1,163 @@
+// 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;
+
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.ir.code.Invoke.Type;
+import com.android.tools.r8.ir.code.Position;
+import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.code.ValueType;
+import com.android.tools.r8.ir.conversion.IRBuilder;
+import com.android.tools.r8.ir.synthetic.SyntheticSourceCode;
+import com.android.tools.r8.utils.IntBox;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceMap.Entry;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Assuming a method signature <code>
+ * void method([args]);
+ * </code>. This class generates code depending on which of the following cases it matches.
+ *
+ * <p>If the method does not override a method and is implemented by many (e.g. 2) classes:
+ *
+ * <pre>
+ * void method([args]) {
+ * switch (classId) {
+ * case 0:
+ * return method$1([args]);
+ * default:
+ * return method$2([args]);
+ * }
+ * }
+ * </pre>
+ *
+ * <p>If the method overrides a method and is implemented by any number of classes:
+ *
+ * <pre>
+ * void method([args]) {
+ * switch (classId) {
+ * case 0:
+ * return method$1([args]);
+ * // ... further cases ...
+ * default:
+ * return super.method$1([args]);
+ * }
+ * }
+ * </pre>
+ */
+public class VirtualMethodEntryPoint extends SyntheticSourceCode {
+ private final Int2ReferenceSortedMap<DexMethod> mappedMethods;
+ private final DexField classIdField;
+ private final DexMethod superMethod;
+
+ public VirtualMethodEntryPoint(
+ Int2ReferenceSortedMap<DexMethod> mappedMethods,
+ DexField classIdField,
+ DexMethod superMethod,
+ DexMethod newMethod,
+ Position callerPosition,
+ DexMethod originalMethod) {
+ super(newMethod.holder, newMethod, callerPosition, originalMethod);
+
+ assert classIdField != null;
+
+ this.mappedMethods = mappedMethods;
+ this.classIdField = classIdField;
+ this.superMethod = superMethod;
+ }
+
+ void addInvokeDirect(DexMethod method) {
+ add(
+ builder -> {
+ List<Value> arguments = new ArrayList<>(method.getArity() + 1);
+ arguments.add(builder.getReceiverValue());
+ if (builder.getArgumentValues() != null) {
+ arguments.addAll(builder.getArgumentValues());
+ }
+ builder.addInvoke(Type.DIRECT, method, method.proto, arguments, false);
+ });
+ }
+
+ void addInvokeSuper() {
+ assert superMethod != null;
+
+ add(
+ builder -> {
+ List<Value> arguments = new ArrayList<>(method.getArity() + 1);
+ arguments.add(builder.getReceiverValue());
+ if (builder.getArgumentValues() != null) {
+ arguments.addAll(builder.getArgumentValues());
+ }
+ builder.addInvoke(Type.SUPER, superMethod, superMethod.proto, arguments, false);
+ });
+ }
+
+ void handleReturn(int retRegister) {
+ if (proto.returnType.isVoidType()) {
+ add(IRBuilder::addReturn, endsBlock);
+ } else {
+ add(builder -> builder.addMoveResult(retRegister));
+ add(builder -> builder.addReturn(retRegister), endsBlock);
+ }
+ }
+
+ @Override
+ protected void prepareInstructions() {
+ int casesCount = mappedMethods.size();
+
+ // If there is no super method, use one of the cases as a fallthrough case.
+ if (superMethod == null) {
+ casesCount--;
+ }
+
+ assert casesCount > 0;
+
+ // Return value register if needed.
+ int returnRegister =
+ !proto.returnType.isVoidType() ? nextRegister(ValueType.fromDexType(proto.returnType)) : -1;
+
+ int[] keys = new int[casesCount];
+ int[] offsets = new int[casesCount];
+ IntBox fallthrough = new IntBox();
+
+ // Fetch the class id from the class id field.
+ int idRegister = nextRegister(ValueType.INT);
+ add(builder -> builder.addInstanceGet(idRegister, getReceiverRegister(), classIdField));
+
+ int switchIndex = lastInstructionIndex();
+ add(
+ builder -> builder.addSwitch(idRegister, keys, fallthrough.get(), offsets),
+ builder -> endsSwitch(builder, switchIndex, fallthrough.get(), offsets));
+
+ int index = 0;
+ for (Entry<DexMethod> entry : mappedMethods.int2ReferenceEntrySet()) {
+ int classId = entry.getIntKey();
+ DexMethod mappedMethod = entry.getValue();
+
+ // If there is no super method, then use the last case as the default case.
+ if (index >= casesCount) {
+ fallthrough.set(nextInstructionIndex());
+ } else {
+ keys[index] = classId;
+ offsets[index] = nextInstructionIndex();
+ }
+
+ addInvokeDirect(mappedMethod);
+ handleReturn(returnRegister);
+
+ index++;
+ }
+
+ // If the super class implements this method, then the fallthrough case should execute it.
+ if (superMethod != null) {
+ fallthrough.set(nextInstructionIndex());
+ addInvokeSuper();
+ handleReturn(returnRegister);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java
new file mode 100644
index 0000000..d6690a9
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodEntryPointSynthesizedCode.java
@@ -0,0 +1,43 @@
+// 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;
+
+import com.android.tools.r8.graph.DexField;
+import com.android.tools.r8.graph.DexMethod;
+import com.android.tools.r8.graph.UseRegistry;
+import com.android.tools.r8.ir.synthetic.SynthesizedCode;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
+import java.util.function.Consumer;
+
+public class VirtualMethodEntryPointSynthesizedCode extends SynthesizedCode {
+ private final Int2ReferenceSortedMap<DexMethod> mappedMethods;
+ private final DexField classIdField;
+
+ public VirtualMethodEntryPointSynthesizedCode(
+ Int2ReferenceSortedMap<DexMethod> mappedMethods,
+ DexField classIdField,
+ DexMethod superMethod,
+ DexMethod method,
+ DexMethod originalMethod) {
+ super(
+ position ->
+ new VirtualMethodEntryPoint(
+ mappedMethods, classIdField, superMethod, method, position, originalMethod));
+
+ this.mappedMethods = mappedMethods;
+ this.classIdField = classIdField;
+ }
+
+ @Override
+ public Consumer<UseRegistry> getRegistryCallback() {
+ return this::registerReachableDefinitions;
+ }
+
+ private void registerReachableDefinitions(UseRegistry registry) {
+ for (DexMethod mappedMethod : mappedMethods.values()) {
+ registry.registerInvokeDirect(mappedMethod);
+ }
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
new file mode 100644
index 0000000..5e20c04f
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/VirtualMethodMerger.java
@@ -0,0 +1,185 @@
+// 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;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexAnnotationSet;
+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.MethodAccessFlags;
+import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
+import com.android.tools.r8.ir.synthetic.AbstractSynthesizedCode;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.shaking.FieldAccessInfoCollectionModifier;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
+import it.unimi.dsi.fastutil.objects.Reference2IntMap;
+import java.util.ArrayList;
+import java.util.Collection;
+
+public class VirtualMethodMerger {
+ private final DexProgramClass target;
+ private final DexItemFactory dexItemFactory;
+ private final Collection<ProgramMethod> methods;
+ private final DexField classIdField;
+ private final AppView<AppInfoWithLiveness> appView;
+ private final DexMethod superMethod;
+
+ public VirtualMethodMerger(
+ AppView<AppInfoWithLiveness> appView,
+ DexProgramClass target,
+ Collection<ProgramMethod> methods,
+ DexField classIdField,
+ DexMethod superMethod) {
+ this.dexItemFactory = appView.dexItemFactory();
+ this.target = target;
+ this.classIdField = classIdField;
+ this.methods = methods;
+ this.appView = appView;
+ this.superMethod = superMethod;
+ }
+
+ public static class Builder {
+ private final Collection<ProgramMethod> methods = new ArrayList<>();
+
+ public Builder add(ProgramMethod constructor) {
+ methods.add(constructor);
+ return this;
+ }
+
+ /** Get the super method handle if this method overrides a parent method. */
+ private DexMethod superMethod(AppView<AppInfoWithLiveness> appView, DexProgramClass target) {
+ // TODO(b/167981556): Correctly detect super methods defined on interfaces.
+ DexMethod template = methods.iterator().next().getReference();
+ SingleResolutionResult resolutionResult =
+ appView
+ .withLiveness()
+ .appInfo()
+ .resolveMethodOnClass(template, target.superType)
+ .asSingleResolution();
+ if (resolutionResult == null) {
+ return null;
+ }
+ return resolutionResult.getResolvedMethod().method;
+ }
+
+ public VirtualMethodMerger build(
+ AppView<AppInfoWithLiveness> appView, DexProgramClass target, DexField classIdField) {
+ DexMethod superMethod = superMethod(appView, target);
+ return new VirtualMethodMerger(appView, target, methods, classIdField, superMethod);
+ }
+ }
+
+ private DexMethod moveMethod(ProgramMethod oldMethod) {
+ DexMethod oldMethodReference = oldMethod.getReference();
+ DexMethod method =
+ dexItemFactory.createFreshMethodName(
+ oldMethodReference.name.toSourceString(),
+ oldMethod.getHolderType(),
+ oldMethodReference.proto,
+ target.type,
+ tryMethod -> target.lookupMethod(tryMethod) == null);
+
+ if (oldMethod.getHolderType() == target.type) {
+ target.removeMethod(oldMethod.getReference());
+ }
+
+ DexEncodedMethod encodedMethod = oldMethod.getDefinition().toTypeSubstitutedMethod(method);
+ MethodAccessFlags flags = encodedMethod.accessFlags;
+ flags.unsetProtected();
+ flags.unsetPublic();
+ flags.setPrivate();
+ target.addDirectMethod(encodedMethod);
+
+ return encodedMethod.method;
+ }
+
+ private MethodAccessFlags getAccessFlags() {
+ // TODO(b/164998929): ensure this behaviour is correct, should probably calculate upper bound
+ return methods.iterator().next().getDefinition().getAccessFlags();
+ }
+
+
+ /**
+ * If there is only a single method that does not override anything then it is safe to just move
+ * it to the target type if it is not already in it.
+ */
+ public void mergeTrivial(HorizontalClassMergerGraphLens.Builder lensBuilder) {
+ ProgramMethod method = methods.iterator().next();
+
+ if (method.getHolderType() != target.type) {
+ // If the method is not in the target type, move it and record it in the lens.
+ DexEncodedMethod newMethod =
+ method.getDefinition().toRenamedHolderMethod(target.type, dexItemFactory);
+ target.addVirtualMethod(newMethod);
+ lensBuilder.moveMethod(method.getReference(), newMethod.getReference());
+ }
+ }
+
+ public void merge(
+ HorizontalClassMergerGraphLens.Builder lensBuilder,
+ FieldAccessInfoCollectionModifier.Builder fieldAccessChangesBuilder,
+ Reference2IntMap classIdentifiers) {
+
+ assert !methods.isEmpty();
+
+ // Handle trivial merges.
+ if (superMethod == null && methods.size() == 1) {
+ mergeTrivial(lensBuilder);
+ return;
+ }
+
+ Int2ReferenceSortedMap<DexMethod> classIdToMethodMap = new Int2ReferenceAVLTreeMap<>();
+
+ int classFileVersion = -1;
+ for (ProgramMethod method : methods) {
+ if (method.getDefinition().hasClassFileVersion()) {
+ classFileVersion =
+ Integer.max(classFileVersion, method.getDefinition().getClassFileVersion());
+ }
+ DexMethod newMethod = moveMethod(method);
+ lensBuilder.recordOriginalSignature(method.getReference(), newMethod);
+ classIdToMethodMap.put(classIdentifiers.getInt(method.getHolderType()), newMethod);
+ }
+
+ // Use the first of the original methods as the original method for the merged constructor.
+ DexMethod originalMethodReference = methods.iterator().next().getReference();
+
+ DexMethod newMethodReference =
+ dexItemFactory.createMethod(
+ target.type, originalMethodReference.proto, originalMethodReference.name);
+ AbstractSynthesizedCode synthesizedCode =
+ new VirtualMethodEntryPointSynthesizedCode(
+ classIdToMethodMap,
+ classIdField,
+ superMethod,
+ newMethodReference,
+ originalMethodReference);
+ DexEncodedMethod newMethod =
+ new DexEncodedMethod(
+ newMethodReference,
+ getAccessFlags(),
+ DexAnnotationSet.empty(),
+ ParameterAnnotationsList.empty(),
+ synthesizedCode,
+ classFileVersion,
+ true);
+
+ // Map each old method to the newly synthesized method in the graph lens.
+ for (ProgramMethod oldMethod : methods) {
+ lensBuilder.mapMethod(oldMethod.getReference(), newMethodReference);
+ }
+ lensBuilder.recordExtraOriginalSignature(originalMethodReference, newMethodReference);
+
+ target.addVirtualMethod(newMethod);
+
+ fieldAccessChangesBuilder.fieldReadByMethod(classIdField, newMethod.method);
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameParentClass.java b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameParentClass.java
index 4e1987e..5b274d1 100644
--- a/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameParentClass.java
+++ b/src/main/java/com/android/tools/r8/horizontalclassmerging/policies/SameParentClass.java
@@ -22,6 +22,7 @@
.computeIfAbsent(clazz.superType, ignore -> new LinkedList<DexProgramClass>())
.add(clazz);
}
+ removeTrivialGroups(groups.values());
return groups.values();
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
index c2ffda0..41a0192 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/AbstractValue.java
@@ -12,14 +12,30 @@
public abstract boolean isNonTrivial();
+ public boolean isSingleBoolean() {
+ return false;
+ }
+
public boolean isBottom() {
return false;
}
- public boolean isZero() {
+ public boolean isFalse() {
return false;
}
+ public boolean isTrue() {
+ return false;
+ }
+
+ public final boolean isNull() {
+ return isFalse();
+ }
+
+ public final boolean isZero() {
+ return isFalse();
+ }
+
/**
* Returns true if this abstract value represents a single concrete value (i.e., the
* concretization of this abstract value has size 1).
diff --git a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
index 98a7fa4..76e6ac8 100644
--- a/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
+++ b/src/main/java/com/android/tools/r8/ir/analysis/value/SingleNumberValue.java
@@ -27,11 +27,21 @@
}
@Override
- public boolean isZero() {
+ public boolean isSingleBoolean() {
+ return isFalse() || isTrue();
+ }
+
+ @Override
+ public boolean isFalse() {
return value == 0;
}
@Override
+ public boolean isTrue() {
+ return value == 1;
+ }
+
+ @Override
public boolean isSingleNumberValue() {
return true;
}
@@ -46,14 +56,26 @@
return value != 0;
}
- public long getValue() {
- return value;
+ public double getDoubleValue() {
+ return Double.longBitsToDouble(value);
+ }
+
+ public float getFloatValue() {
+ return Float.intBitsToFloat((int) value);
}
public int getIntValue() {
return (int) value;
}
+ public long getLongValue() {
+ return value;
+ }
+
+ public long getValue() {
+ return value;
+ }
+
@Override
public boolean equals(Object o) {
return this == o;
diff --git a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
index 3d7ae52..23808f4 100644
--- a/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
+++ b/src/main/java/com/android/tools/r8/ir/code/InstanceOf.java
@@ -121,4 +121,10 @@
public boolean instructionMayTriggerMethodInvocation(AppView<?> appView, ProgramMethod context) {
return false;
}
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder(super.toString());
+ return builder.append("; ").append(type.toSourceString()).toString();
+ }
}
diff --git a/src/main/java/com/android/tools/r8/ir/code/Invoke.java b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
index 1c19488..0e40a2a 100644
--- a/src/main/java/com/android/tools/r8/ir/code/Invoke.java
+++ b/src/main/java/com/android/tools/r8/ir/code/Invoke.java
@@ -3,6 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.ir.code;
+import com.android.tools.r8.code.InvokeCustomRange;
+import com.android.tools.r8.code.InvokeDirectRange;
+import com.android.tools.r8.code.InvokeInterfaceRange;
+import com.android.tools.r8.code.InvokePolymorphicRange;
+import com.android.tools.r8.code.InvokeStaticRange;
+import com.android.tools.r8.code.InvokeSuperRange;
+import com.android.tools.r8.code.InvokeVirtualRange;
import com.android.tools.r8.code.MoveResult;
import com.android.tools.r8.code.MoveResultObject;
import com.android.tools.r8.code.MoveResultWide;
@@ -20,19 +27,60 @@
import com.android.tools.r8.ir.conversion.DexBuilder;
import java.util.List;
import java.util.Set;
+import org.objectweb.asm.Opcodes;
public abstract class Invoke extends Instruction {
+ private static final int NO_SUCH_DEX_INSTRUCTION = -1;
+
public enum Type {
- DIRECT,
- INTERFACE,
- STATIC,
- SUPER,
- VIRTUAL,
- NEW_ARRAY,
- MULTI_NEW_ARRAY,
- CUSTOM,
- POLYMORPHIC;
+ DIRECT(com.android.tools.r8.code.InvokeDirect.OPCODE, InvokeDirectRange.OPCODE),
+ INTERFACE(com.android.tools.r8.code.InvokeInterface.OPCODE, InvokeInterfaceRange.OPCODE),
+ STATIC(com.android.tools.r8.code.InvokeStatic.OPCODE, InvokeStaticRange.OPCODE),
+ SUPER(com.android.tools.r8.code.InvokeSuper.OPCODE, InvokeSuperRange.OPCODE),
+ VIRTUAL(com.android.tools.r8.code.InvokeVirtual.OPCODE, InvokeVirtualRange.OPCODE),
+ NEW_ARRAY(com.android.tools.r8.code.NewArray.OPCODE, NO_SUCH_DEX_INSTRUCTION),
+ MULTI_NEW_ARRAY(NO_SUCH_DEX_INSTRUCTION, NO_SUCH_DEX_INSTRUCTION),
+ CUSTOM(com.android.tools.r8.code.InvokeCustom.OPCODE, InvokeCustomRange.OPCODE),
+ POLYMORPHIC(com.android.tools.r8.code.InvokePolymorphic.OPCODE, InvokePolymorphicRange.OPCODE);
+
+ private final int dexOpcode;
+ private final int dexOpcodeRange;
+
+ Type(int dexOpcode, int dexOpcodeRange) {
+ this.dexOpcode = dexOpcode;
+ this.dexOpcodeRange = dexOpcodeRange;
+ }
+
+ public int getCfOpcode() {
+ switch (this) {
+ case DIRECT:
+ return Opcodes.INVOKESPECIAL;
+ case INTERFACE:
+ return Opcodes.INVOKEINTERFACE;
+ case STATIC:
+ return Opcodes.INVOKESTATIC;
+ case SUPER:
+ return Opcodes.INVOKESPECIAL;
+ case VIRTUAL:
+ return Opcodes.INVOKEVIRTUAL;
+ case NEW_ARRAY:
+ case MULTI_NEW_ARRAY:
+ case POLYMORPHIC:
+ default:
+ throw new Unreachable();
+ }
+ }
+
+ public int getDexOpcode() {
+ assert dexOpcode >= 0;
+ return dexOpcode;
+ }
+
+ public int getDexOpcodeRange() {
+ assert dexOpcodeRange >= 0;
+ return dexOpcodeRange;
+ }
public MethodHandleType toMethodHandle(DexMethod targetMethod) {
switch (this) {
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
index 52ab07a..f5a51c8 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/CallGraphBuilderBase.java
@@ -273,7 +273,7 @@
}
FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(encodedField.field);
- if (fieldAccessInfo != null) {
+ if (fieldAccessInfo != null && fieldAccessInfo.hasKnownWriteContexts()) {
if (fieldAccessInfo.getNumberOfWriteContexts() == 1) {
fieldAccessInfo.forEachWriteContext(this::addFieldReadEdge);
}
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 4c10624..5107d27 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,6 +3,7 @@
// 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;
@@ -90,6 +91,7 @@
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;
import com.android.tools.r8.utils.DescriptorUtils;
@@ -190,7 +192,7 @@
* (i.e., whether we are running R8). See {@link AppView#enableWholeProgramOptimizations()}.
*/
public IRConverter(
- AppView<?> appView, Timing timing, CfgPrinter printer, MainDexClasses mainDexClasses) {
+ AppView<?> appView, Timing timing, CfgPrinter printer, MainDexTracingResult mainDexClasses) {
assert appView.appInfo().hasLiveness() || appView.graphLens().isIdentityLens();
assert appView.options() != null;
assert appView.options().programConsumer != null;
@@ -309,7 +311,7 @@
this.memberValuePropagation =
options.enableValuePropagation ? new MemberValuePropagation(appViewWithLiveness) : null;
this.methodOptimizationInfoCollector =
- new MethodOptimizationInfoCollector(appViewWithLiveness);
+ new MethodOptimizationInfoCollector(appViewWithLiveness, this);
if (options.isMinifying()) {
this.identifierNameStringMarker = new IdentifierNameStringMarker(appViewWithLiveness);
} else {
@@ -364,16 +366,16 @@
/** Create an IR converter for processing methods with full program optimization disabled. */
public IRConverter(AppView<?> appView, Timing timing) {
- this(appView, timing, null, MainDexClasses.NONE);
+ this(appView, timing, null, MainDexTracingResult.NONE);
}
/** Create an IR converter for processing methods with full program optimization disabled. */
public IRConverter(AppView<?> appView, Timing timing, CfgPrinter printer) {
- this(appView, timing, printer, MainDexClasses.NONE);
+ this(appView, timing, printer, MainDexTracingResult.NONE);
}
public IRConverter(AppInfo appInfo, Timing timing, CfgPrinter printer) {
- this(AppView.createForD8(appInfo), timing, printer, MainDexClasses.NONE);
+ this(AppView.createForD8(appInfo), timing, printer, MainDexTracingResult.NONE);
}
private boolean enableTwrCloseResourceDesugaring() {
@@ -493,42 +495,54 @@
processCovariantReturnTypeAnnotations(builder);
generateDesugaredLibraryAPIWrappers(builder, executor);
- handleSynthesizedClassMapping(builder);
+ handleSynthesizedClassMapping(appView, builder);
timing.end();
DexApplication app = builder.build();
- appView.setAppInfo(new AppInfo(app, appView.appInfo().getSyntheticItems().commit(app)));
+ appView.setAppInfo(
+ new AppInfo(
+ app,
+ appView.appInfo().getMainDexClasses(),
+ appView.appInfo().getSyntheticItems().commit(app)));
}
- private void handleSynthesizedClassMapping(Builder<?> builder) {
+ private void handleSynthesizedClassMapping(AppView<?> appView, Builder<?> builder) {
if (options.intermediate) {
updateSynthesizedClassMapping(builder);
}
- updateMainDexListWithSynthesizedClassMap(builder);
+ updateMainDexListWithSynthesizedClassMap(appView, builder);
if (!options.intermediate) {
clearSynthesizedClassMapping(builder);
}
}
- private void updateMainDexListWithSynthesizedClassMap(Builder<?> builder) {
- Set<DexType> inputMainDexList = builder.getMainDexList();
- if (!inputMainDexList.isEmpty()) {
- Map<DexType, DexProgramClass> programClasses = builder.getProgramClasses().stream()
- .collect(Collectors.toMap(
- programClass -> programClass.type,
- Function.identity()));
- Collection<DexType> synthesized = new ArrayList<>();
- for (DexType dexType : inputMainDexList) {
- DexProgramClass programClass = programClasses.get(dexType);
- if (programClass != null) {
- synthesized.addAll(DexAnnotation.readAnnotationSynthesizedClassMap(
- programClass, builder.dexItemFactory));
- }
- }
- builder.addToMainDexList(synthesized);
+ 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) {
@@ -558,8 +572,7 @@
.stream()
.map(dexProgramClass -> dexProgramClass.type)
.forEach(synthesized::add);
- synthesized.addAll(
- DexAnnotation.readAnnotationSynthesizedClassMap(original, builder.dexItemFactory));
+ synthesized.addAll(readAnnotationSynthesizedClassMap(original, builder.dexItemFactory));
DexAnnotation updatedAnnotation =
DexAnnotation.createAnnotationSynthesizedClassMap(synthesized, builder.dexItemFactory);
@@ -589,52 +602,53 @@
private void convertMethod(ProgramMethod method) {
DexEncodedMethod definition = method.getDefinition();
- if (definition.getCode() != null) {
- boolean matchesMethodFilter = options.methodMatchesFilter(definition);
- if (matchesMethodFilter) {
- if (appView.options().enableNeverMergePrefixes) {
- for (DexString neverMergePrefix : neverMergePrefixes) {
- // Synthetic classes will always be merged.
- if (appView.appInfo().getSyntheticItems().isSyntheticClass(method.getHolder())) {
- continue;
- }
- if (method.getHolderType().descriptor.startsWith(neverMergePrefix)) {
- seenNeverMergePrefix.getAndSet(true);
- } else {
- seenNotNeverMergePrefix.getAndSet(true);
- }
- // Don't mix.
- if (seenNeverMergePrefix.get() && seenNotNeverMergePrefix.get()) {
- StringBuilder message = new StringBuilder();
- message
- .append("Merging dex file containing classes with prefix")
- .append(neverMergePrefixes.size() > 1 ? "es " : " ");
- for (int i = 0; i < neverMergePrefixes.size(); i++) {
- message
- .append("'")
- .append(neverMergePrefixes.get(0).toString().substring(1).replace('/', '.'))
- .append("'")
- .append(i < neverMergePrefixes.size() - 1 ? ", " : "");
- }
- message.append(" with classes with any other prefixes is not allowed.");
- throw new CompilationError(message.toString());
- }
- }
+ if (definition.getCode() == null) {
+ return;
+ }
+ if (!options.methodMatchesFilter(definition)) {
+ return;
+ }
+ checkPrefixMerging(method);
+ if (options.isGeneratingClassFiles()
+ || !(options.passthroughDexCode && definition.getCode().isDexCode())) {
+ // We do not process in call graph order, so anything could be a leaf.
+ rewriteCode(
+ method, simpleOptimizationFeedback, OneTimeMethodProcessor.create(method, appView), null);
+ } else {
+ assert definition.getCode().isDexCode();
+ }
+ if (!options.isGeneratingClassFiles()) {
+ updateHighestSortingStrings(definition);
+ }
+ }
+
+ private void checkPrefixMerging(ProgramMethod method) {
+ if (!appView.options().enableNeverMergePrefixes) {
+ return;
+ }
+ for (DexString neverMergePrefix : neverMergePrefixes) {
+ if (method.getHolderType().descriptor.startsWith(neverMergePrefix)) {
+ seenNeverMergePrefix.getAndSet(true);
+ } else {
+ seenNotNeverMergePrefix.getAndSet(true);
+ }
+ // Don't mix.
+ // TODO(b/168001352): Consider requiring that no 'never merge' prefix is ever seen as a
+ // passthrough object.
+ if (seenNeverMergePrefix.get() && seenNotNeverMergePrefix.get()) {
+ StringBuilder message = new StringBuilder();
+ message
+ .append("Merging dex file containing classes with prefix")
+ .append(neverMergePrefixes.size() > 1 ? "es " : " ");
+ for (int i = 0; i < neverMergePrefixes.size(); i++) {
+ message
+ .append("'")
+ .append(neverMergePrefixes.get(0).toString().substring(1).replace('/', '.'))
+ .append("'")
+ .append(i < neverMergePrefixes.size() - 1 ? ", " : "");
}
- if (options.isGeneratingClassFiles()
- || !(options.passthroughDexCode && definition.getCode().isDexCode())) {
- // We do not process in call graph order, so anything could be a leaf.
- rewriteCode(
- method,
- simpleOptimizationFeedback,
- OneTimeMethodProcessor.create(method, appView),
- null);
- } else {
- assert definition.getCode().isDexCode();
- }
- if (!options.isGeneratingClassFiles()) {
- updateHighestSortingStrings(definition);
- }
+ message.append(" with classes with any other prefixes is not allowed.");
+ throw new CompilationError(message.toString());
}
}
}
@@ -716,6 +730,9 @@
assert graphLensForIR == appView.graphLens();
}
+ // The field access info collection is not maintained during IR processing.
+ appView.appInfo().withLiveness().getFieldAccessInfoCollection().destroyAccessContexts();
+
// Assure that no more optimization feedback left after primary processing.
assert feedback.noUpdatesLeft();
appView.setAllCodeProcessed();
@@ -789,7 +806,7 @@
synthesizeTwrCloseResourceUtilityClass(builder, executorService);
synthesizeJava8UtilityClass(builder, executorService);
synthesizeRetargetClass(builder, executorService);
- handleSynthesizedClassMapping(builder);
+ handleSynthesizedClassMapping(appView, builder);
synthesizeEnumUnboxingUtilityMethods(builder, executorService);
printPhase("Lambda merging finalization");
@@ -800,10 +817,10 @@
generateDesugaredLibraryAPIWrappers(builder, executorService);
if (serviceLoaderRewriter != null && serviceLoaderRewriter.getSynthesizedClass() != null) {
- appView.appInfo().addSynthesizedClass(serviceLoaderRewriter.getSynthesizedClass());
+ appView.appInfo().addSynthesizedClass(serviceLoaderRewriter.getSynthesizedClass(), true);
processSynthesizedServiceLoaderMethods(
serviceLoaderRewriter.getSynthesizedClass(), executorService);
- builder.addSynthesizedClass(serviceLoaderRewriter.getSynthesizedClass(), true);
+ builder.addSynthesizedClass(serviceLoaderRewriter.getSynthesizedClass());
}
// Update optimization info for all synthesized methods at once.
@@ -823,7 +840,7 @@
},
executorService);
DexProgramClass outlineClass = outliner.buildOutlinerClass(computeOutlineClassType());
- appView.appInfo().addSynthesizedClass(outlineClass);
+ appView.appInfo().addSynthesizedClass(outlineClass, true);
optimizeSynthesizedClass(outlineClass, executorService);
forEachSelectedOutliningMethod(
methodsSelectedForOutlining,
@@ -836,7 +853,7 @@
executorService);
feedback.updateVisibleOptimizationInfo();
assert outliner.checkAllOutlineSitesFoundAgain();
- builder.addSynthesizedClass(outlineClass, true);
+ builder.addSynthesizedClass(outlineClass);
clearDexMethodCompilationState(outlineClass);
}
timing.end();
@@ -1239,7 +1256,7 @@
assert appView.enableWholeProgramOptimizations();
timing.begin("Collect optimization info");
collectOptimizationInfo(
- method, code, ClassInitializerDefaultsResult.empty(), feedback, methodProcessor, timing);
+ context, code, ClassInitializerDefaultsResult.empty(), feedback, methodProcessor, timing);
timing.end();
return timing;
}
@@ -1601,7 +1618,7 @@
if (appView.enableWholeProgramOptimizations()) {
timing.begin("Collect optimization info");
collectOptimizationInfo(
- method, code, classInitializerDefaultsResult, feedback, methodProcessor, timing);
+ context, code, classInitializerDefaultsResult, feedback, methodProcessor, timing);
timing.end();
}
@@ -1636,7 +1653,7 @@
// Compute optimization info summary for the current method unless it is pinned
// (in that case we should not be making any assumptions about the behavior of the method).
public void collectOptimizationInfo(
- DexEncodedMethod method,
+ ProgramMethod method,
IRCode code,
ClassInitializerDefaultsResult classInitializerDefaultsResult,
OptimizationFeedback feedback,
@@ -1658,7 +1675,8 @@
}
// Arguments can be changed during the debug mode.
- boolean isDebugMode = options.debug || method.getOptimizationInfo().isReachabilitySensitive();
+ boolean isDebugMode =
+ options.debug || method.getDefinition().getOptimizationInfo().isReachabilitySensitive();
if (!isDebugMode && appView.callSiteOptimizationInfoPropagator() != null) {
timing.begin("Collect call-site info");
appView.callSiteOptimizationInfoPropagator().collectCallSiteOptimizationInfo(code, timing);
@@ -1670,8 +1688,8 @@
}
InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos = null;
- if (method.isInitializer()) {
- if (method.isClassInitializer()) {
+ if (method.getDefinition().isInitializer()) {
+ if (method.getDefinition().isClassInitializer()) {
StaticFieldValueAnalysis.run(
appView, code, classInitializerDefaultsResult, feedback, timing);
} else {
@@ -1681,12 +1699,7 @@
}
}
methodOptimizationInfoCollector.collectMethodOptimizationInfo(
- code.method(),
- code,
- feedback,
- dynamicTypeOptimization,
- instanceFieldInitializationInfos,
- timing);
+ method, code, feedback, dynamicTypeOptimization, instanceFieldInitializationInfos, timing);
}
public void removeDeadCodeAndFinalizeIR(
@@ -1744,7 +1757,7 @@
timing.end();
}
- private void markProcessed(IRCode code, OptimizationFeedback feedback) {
+ public void markProcessed(IRCode code, OptimizationFeedback feedback) {
// After all the optimizations have take place, we compute whether method should be inlined.
ProgramMethod method = code.context();
ConstraintWithTarget state =
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
index 51905bf..576a376 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriter.java
@@ -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.UseRegistry.MethodHandleUse.ARGUMENT_TO_LAMBDA_METAFACTORY;
import static com.android.tools.r8.graph.UseRegistry.MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
import static com.android.tools.r8.ir.code.Invoke.Type.STATIC;
import static com.android.tools.r8.ir.code.Invoke.Type.VIRTUAL;
@@ -41,13 +40,7 @@
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexMethod;
import com.android.tools.r8.graph.DexMethodHandle;
-import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
-import com.android.tools.r8.graph.DexProto;
import com.android.tools.r8.graph.DexType;
-import com.android.tools.r8.graph.DexValue;
-import com.android.tools.r8.graph.DexValue.DexValueMethodHandle;
-import com.android.tools.r8.graph.DexValue.DexValueMethodType;
-import com.android.tools.r8.graph.DexValue.DexValueType;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult;
import com.android.tools.r8.graph.ProgramMethod;
@@ -55,7 +48,6 @@
import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfo;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.ArgumentInfoCollection;
import com.android.tools.r8.graph.RewrittenPrototypeDescription.RewrittenTypeInfo;
-import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
import com.android.tools.r8.graph.classmerging.VerticallyMergedClasses;
import com.android.tools.r8.ir.analysis.type.DestructivePhiTypeUpdater;
import com.android.tools.r8.ir.analysis.type.TypeElement;
@@ -101,7 +93,6 @@
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
import java.util.function.BiFunction;
public class LensCodeRewriter {
@@ -109,11 +100,12 @@
private final AppView<? extends AppInfoWithClassHierarchy> appView;
private final EnumUnboxer enumUnboxer;
- private final Map<DexProto, DexProto> protoFixupCache = new ConcurrentHashMap<>();
+ private final LensCodeRewriterUtils helper;
LensCodeRewriter(AppView<? extends AppInfoWithClassHierarchy> appView, EnumUnboxer enumUnboxer) {
this.appView = appView;
this.enumUnboxer = enumUnboxer;
+ this.helper = new LensCodeRewriterUtils(appView);
}
private Value makeOutValue(Instruction insn, IRCode code) {
@@ -152,7 +144,7 @@
{
InvokeCustom invokeCustom = current.asInvokeCustom();
DexCallSite callSite = invokeCustom.getCallSite();
- DexCallSite newCallSite = rewriteCallSite(callSite, method);
+ DexCallSite newCallSite = helper.rewriteCallSite(callSite, method);
if (newCallSite != callSite) {
Value newOutValue = makeOutValue(invokeCustom, code);
InvokeCustom newInvokeCustom =
@@ -169,7 +161,7 @@
{
DexMethodHandle handle = current.asConstMethodHandle().getValue();
DexMethodHandle newHandle =
- rewriteDexMethodHandle(handle, method, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY);
+ helper.rewriteDexMethodHandle(handle, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, method);
if (newHandle != handle) {
Value newOutValue = makeOutValue(current, code);
iterator.replaceCurrentInstruction(new ConstMethodHandle(newOutValue, newHandle));
@@ -632,28 +624,6 @@
return TypeElement.getNull();
}
- public DexCallSite rewriteCallSite(DexCallSite callSite, ProgramMethod context) {
- DexItemFactory dexItemFactory = appView.dexItemFactory();
- DexProto newMethodProto =
- dexItemFactory.applyClassMappingToProto(
- callSite.methodProto, appView.graphLens()::lookupType, protoFixupCache);
- DexMethodHandle newBootstrapMethod =
- rewriteDexMethodHandle(
- callSite.bootstrapMethod, context, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY);
- boolean isLambdaMetaFactory =
- dexItemFactory.isLambdaMetafactoryMethod(callSite.bootstrapMethod.asMethod());
- MethodHandleUse methodHandleUse =
- isLambdaMetaFactory ? ARGUMENT_TO_LAMBDA_METAFACTORY : NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
- List<DexValue> newArgs = rewriteBootstrapArgs(callSite.bootstrapArgs, context, methodHandleUse);
- if (!newMethodProto.equals(callSite.methodProto)
- || newBootstrapMethod != callSite.bootstrapMethod
- || !newArgs.equals(callSite.bootstrapArgs)) {
- return dexItemFactory.createCallSite(
- callSite.methodName, newMethodProto, newBootstrapMethod, newArgs);
- }
- return callSite;
- }
-
// If the given invoke is on the form "invoke-direct A.<init>, v0, ..." and the definition of
// value v0 is "new-instance v0, B", where B is a subtype of A (see the Art800 and B116282409
// tests), then fail with a compilation error if A has previously been merged into B.
@@ -731,116 +701,6 @@
return !deadCatchHandlers.isEmpty();
}
- private List<DexValue> rewriteBootstrapArgs(
- List<DexValue> bootstrapArgs, ProgramMethod method, MethodHandleUse use) {
- List<DexValue> newBootstrapArgs = null;
- boolean changed = false;
- for (int i = 0; i < bootstrapArgs.size(); i++) {
- DexValue argument = bootstrapArgs.get(i);
- DexValue newArgument = null;
- switch (argument.getValueKind()) {
- case METHOD_HANDLE:
- newArgument = rewriteDexValueMethodHandle(argument.asDexValueMethodHandle(), method, use);
- break;
- case METHOD_TYPE:
- newArgument = rewriteDexMethodType(argument.asDexValueMethodType());
- break;
- case TYPE:
- DexType oldType = argument.asDexValueType().value;
- DexType newType = appView.graphLens().lookupType(oldType);
- if (newType != oldType) {
- newArgument = new DexValueType(newType);
- }
- break;
- default:
- // Intentionally empty.
- }
- if (newArgument != null) {
- if (newBootstrapArgs == null) {
- newBootstrapArgs = new ArrayList<>(bootstrapArgs.subList(0, i));
- }
- newBootstrapArgs.add(newArgument);
- changed = true;
- } else if (newBootstrapArgs != null) {
- newBootstrapArgs.add(argument);
- }
- }
- return changed ? newBootstrapArgs : bootstrapArgs;
- }
-
- private DexValueMethodHandle rewriteDexValueMethodHandle(
- DexValueMethodHandle methodHandle, ProgramMethod context, MethodHandleUse use) {
- DexMethodHandle oldHandle = methodHandle.value;
- DexMethodHandle newHandle = rewriteDexMethodHandle(oldHandle, context, use);
- return newHandle != oldHandle ? new DexValueMethodHandle(newHandle) : methodHandle;
- }
-
- private DexMethodHandle rewriteDexMethodHandle(
- DexMethodHandle methodHandle, ProgramMethod context, MethodHandleUse use) {
- if (methodHandle.isMethodHandle()) {
- DexMethod invokedMethod = methodHandle.asMethod();
- MethodHandleType oldType = methodHandle.type;
- GraphLensLookupResult lensLookup =
- appView
- .graphLens()
- .lookupMethod(invokedMethod, context.getReference(), oldType.toInvokeType());
- DexMethod rewrittenTarget = lensLookup.getMethod();
- DexMethod actualTarget;
- MethodHandleType newType;
- if (use == ARGUMENT_TO_LAMBDA_METAFACTORY) {
- // Lambda metafactory arguments will be lambda desugared away and therefore cannot flow
- // to a MethodHandle.invokeExact call. We can therefore member-rebind with no issues.
- actualTarget = rewrittenTarget;
- newType = lensLookup.getType().toMethodHandle(actualTarget);
- } else {
- assert use == NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
- // MethodHandles that are not arguments to a lambda metafactory will not be desugared
- // away. Therefore they could flow to a MethodHandle.invokeExact call which means that
- // we cannot member rebind. We therefore keep the receiver and also pin the receiver
- // with a keep rule (see Enqueuer.registerMethodHandle).
- actualTarget =
- appView
- .dexItemFactory()
- .createMethod(invokedMethod.holder, rewrittenTarget.proto, rewrittenTarget.name);
- newType = oldType;
- if (oldType.isInvokeDirect()) {
- // For an invoke direct, the rewritten target must have the same holder as the original.
- // If the method has changed from private to public we need to use virtual instead of
- // direct.
- assert rewrittenTarget.holder == actualTarget.holder;
- newType = lensLookup.getType().toMethodHandle(actualTarget);
- assert newType == MethodHandleType.INVOKE_DIRECT
- || newType == MethodHandleType.INVOKE_INSTANCE;
- }
- }
- if (newType != oldType || actualTarget != invokedMethod || rewrittenTarget != actualTarget) {
- DexClass holder = appView.definitionFor(actualTarget.holder);
- boolean isInterface = holder != null ? holder.isInterface() : methodHandle.isInterface;
- return new DexMethodHandle(
- newType,
- actualTarget,
- isInterface,
- rewrittenTarget != actualTarget ? rewrittenTarget : null);
- }
- } else {
- DexField field = methodHandle.asField();
- DexField actualField = appView.graphLens().lookupField(field);
- if (actualField != field) {
- return new DexMethodHandle(methodHandle.type, actualField, methodHandle.isInterface);
- }
- }
- return methodHandle;
- }
-
- private DexValueMethodType rewriteDexMethodType(DexValueMethodType type) {
- DexProto oldProto = type.value;
- DexProto newProto =
- appView
- .dexItemFactory()
- .applyClassMappingToProto(oldProto, appView.graphLens()::lookupType, protoFixupCache);
- return newProto != oldProto ? new DexValueMethodType(newProto) : type;
- }
-
class InstructionReplacer {
private final IRCode code;
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
new file mode 100644
index 0000000..27b3064
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/conversion/LensCodeRewriterUtils.java
@@ -0,0 +1,180 @@
+// 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.conversion;
+
+import static com.android.tools.r8.graph.UseRegistry.MethodHandleUse.ARGUMENT_TO_LAMBDA_METAFACTORY;
+import static com.android.tools.r8.graph.UseRegistry.MethodHandleUse.NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
+
+import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.DexCallSite;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexDefinitionSupplier;
+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.DexMethodHandle;
+import com.android.tools.r8.graph.DexMethodHandle.MethodHandleType;
+import com.android.tools.r8.graph.DexProto;
+import com.android.tools.r8.graph.DexType;
+import com.android.tools.r8.graph.DexValue;
+import com.android.tools.r8.graph.DexValue.DexValueMethodHandle;
+import com.android.tools.r8.graph.DexValue.DexValueMethodType;
+import com.android.tools.r8.graph.DexValue.DexValueType;
+import com.android.tools.r8.graph.GraphLens;
+import com.android.tools.r8.graph.GraphLens.GraphLensLookupResult;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.graph.UseRegistry.MethodHandleUse;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+public class LensCodeRewriterUtils {
+
+ private final DexDefinitionSupplier definitions;
+ private final GraphLens graphLens;
+
+ private final Map<DexProto, DexProto> protoFixupCache = new ConcurrentHashMap<>();
+
+ public LensCodeRewriterUtils(AppView<?> appView) {
+ this(appView, appView.graphLens());
+ }
+
+ public LensCodeRewriterUtils(DexDefinitionSupplier definitions, GraphLens graphLens) {
+ this.definitions = definitions;
+ this.graphLens = graphLens;
+ }
+
+ public DexCallSite rewriteCallSite(DexCallSite callSite, ProgramMethod context) {
+ DexItemFactory dexItemFactory = definitions.dexItemFactory();
+ DexProto newMethodProto = rewriteProto(callSite.methodProto);
+ DexMethodHandle newBootstrapMethod =
+ rewriteDexMethodHandle(
+ callSite.bootstrapMethod, NOT_ARGUMENT_TO_LAMBDA_METAFACTORY, context);
+ boolean isLambdaMetaFactory =
+ dexItemFactory.isLambdaMetafactoryMethod(callSite.bootstrapMethod.asMethod());
+ MethodHandleUse methodHandleUse =
+ isLambdaMetaFactory ? ARGUMENT_TO_LAMBDA_METAFACTORY : NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
+ List<DexValue> newArgs =
+ rewriteBootstrapArguments(callSite.bootstrapArgs, methodHandleUse, context);
+ if (!newMethodProto.equals(callSite.methodProto)
+ || newBootstrapMethod != callSite.bootstrapMethod
+ || !newArgs.equals(callSite.bootstrapArgs)) {
+ return dexItemFactory.createCallSite(
+ callSite.methodName, newMethodProto, newBootstrapMethod, newArgs);
+ }
+ return callSite;
+ }
+
+ public DexMethodHandle rewriteDexMethodHandle(
+ DexMethodHandle methodHandle, MethodHandleUse use, ProgramMethod context) {
+ if (methodHandle.isMethodHandle()) {
+ DexMethod invokedMethod = methodHandle.asMethod();
+ MethodHandleType oldType = methodHandle.type;
+ GraphLensLookupResult lensLookup =
+ graphLens.lookupMethod(invokedMethod, context.getReference(), oldType.toInvokeType());
+ DexMethod rewrittenTarget = lensLookup.getMethod();
+ DexMethod actualTarget;
+ MethodHandleType newType;
+ if (use == ARGUMENT_TO_LAMBDA_METAFACTORY) {
+ // Lambda metafactory arguments will be lambda desugared away and therefore cannot flow
+ // to a MethodHandle.invokeExact call. We can therefore member-rebind with no issues.
+ actualTarget = rewrittenTarget;
+ newType = lensLookup.getType().toMethodHandle(actualTarget);
+ } else {
+ assert use == NOT_ARGUMENT_TO_LAMBDA_METAFACTORY;
+ // MethodHandles that are not arguments to a lambda metafactory will not be desugared
+ // away. Therefore they could flow to a MethodHandle.invokeExact call which means that
+ // we cannot member rebind. We therefore keep the receiver and also pin the receiver
+ // with a keep rule (see Enqueuer.registerMethodHandle).
+ actualTarget =
+ definitions
+ .dexItemFactory()
+ .createMethod(invokedMethod.holder, rewrittenTarget.proto, rewrittenTarget.name);
+ newType = oldType;
+ if (oldType.isInvokeDirect()) {
+ // For an invoke direct, the rewritten target must have the same holder as the original.
+ // If the method has changed from private to public we need to use virtual instead of
+ // direct.
+ assert rewrittenTarget.holder == actualTarget.holder;
+ newType = lensLookup.getType().toMethodHandle(actualTarget);
+ assert newType == MethodHandleType.INVOKE_DIRECT
+ || newType == MethodHandleType.INVOKE_INSTANCE;
+ }
+ }
+ if (newType != oldType || actualTarget != invokedMethod || rewrittenTarget != actualTarget) {
+ DexClass holder = definitions.definitionFor(actualTarget.holder, context);
+ boolean isInterface = holder != null ? holder.isInterface() : methodHandle.isInterface;
+ return new DexMethodHandle(
+ newType,
+ actualTarget,
+ isInterface,
+ rewrittenTarget != actualTarget ? rewrittenTarget : null);
+ }
+ } else {
+ DexField field = methodHandle.asField();
+ DexField actualField = graphLens.lookupField(field);
+ if (actualField != field) {
+ return new DexMethodHandle(methodHandle.type, actualField, methodHandle.isInterface);
+ }
+ }
+ return methodHandle;
+ }
+
+ private List<DexValue> rewriteBootstrapArguments(
+ List<DexValue> bootstrapArgs, MethodHandleUse use, ProgramMethod context) {
+ List<DexValue> newBootstrapArgs = null;
+ boolean changed = false;
+ for (int i = 0; i < bootstrapArgs.size(); i++) {
+ DexValue argument = bootstrapArgs.get(i);
+ DexValue newArgument = rewriteBootstrapArgument(argument, use, context);
+ if (newArgument != argument) {
+ if (newBootstrapArgs == null) {
+ newBootstrapArgs = new ArrayList<>(bootstrapArgs.subList(0, i));
+ }
+ newBootstrapArgs.add(newArgument);
+ changed = true;
+ } else if (newBootstrapArgs != null) {
+ newBootstrapArgs.add(newArgument);
+ }
+ }
+ return changed ? newBootstrapArgs : bootstrapArgs;
+ }
+
+ private DexValueMethodType rewriteDexMethodType(DexValueMethodType type) {
+ DexProto oldProto = type.value;
+ DexProto newProto = rewriteProto(oldProto);
+ return newProto != oldProto ? new DexValueMethodType(newProto) : type;
+ }
+
+ private DexValue rewriteBootstrapArgument(
+ DexValue value, MethodHandleUse use, ProgramMethod context) {
+ switch (value.getValueKind()) {
+ case METHOD_HANDLE:
+ return rewriteDexValueMethodHandle(value.asDexValueMethodHandle(), use, context);
+ case METHOD_TYPE:
+ return rewriteDexMethodType(value.asDexValueMethodType());
+ case TYPE:
+ DexType oldType = value.asDexValueType().value;
+ DexType newType = graphLens.lookupType(oldType);
+ return newType != oldType ? new DexValueType(newType) : value;
+ default:
+ return value;
+ }
+ }
+
+ public DexProto rewriteProto(DexProto proto) {
+ return definitions
+ .dexItemFactory()
+ .applyClassMappingToProto(proto, graphLens::lookupType, protoFixupCache);
+ }
+
+ private DexValueMethodHandle rewriteDexValueMethodHandle(
+ DexValueMethodHandle methodHandle, MethodHandleUse use, ProgramMethod context) {
+ DexMethodHandle oldHandle = methodHandle.value;
+ DexMethodHandle newHandle = rewriteDexMethodHandle(oldHandle, use, context);
+ return newHandle != oldHandle ? new DexValueMethodHandle(newHandle) : methodHandle;
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
index e54ec6c..4379da1 100644
--- a/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
+++ b/src/main/java/com/android/tools/r8/ir/conversion/MethodOptimizationFeedback.java
@@ -35,6 +35,8 @@
void methodReturnsAbstractValue(
DexEncodedMethod method, AppView<AppInfoWithLiveness> appView, AbstractValue abstractValue);
+ void unsetAbstractReturnValue(DexEncodedMethod method);
+
void methodReturnsObjectWithUpperBoundType(
DexEncodedMethod method, AppView<?> appView, TypeElement type);
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 347f495..5c08f1f 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
@@ -221,9 +221,8 @@
ParameterAnnotationsList.empty(),
code,
true);
- boolean addToMainDexList =
- referencingClasses.stream()
- .anyMatch(clazz -> appView.appInfo().isInMainDexList(clazz.type));
+ boolean addToMainDexClasses =
+ appView.appInfo().getMainDexClasses().containsAnyOf(referencingClasses);
DexProgramClass utilityClass =
synthesizeClassWithUniqueMethod(
builder,
@@ -231,7 +230,7 @@
method.holder,
dexEncodedMethod,
"java8 methods utility class",
- addToMainDexList,
+ addToMainDexClasses,
appView);
// The following may add elements to methodsProviders.
converter.optimizeSynthesizedClass(utilityClass, executorService);
@@ -244,7 +243,7 @@
DexType type,
DexEncodedMethod uniqueMethod,
String origin,
- boolean addToMainDexList,
+ boolean addToMainDexClasses,
AppView<?> appView) {
DexItemFactory factory = appView.dexItemFactory();
DexProgramClass newClass =
@@ -271,8 +270,8 @@
: new DexEncodedMethod[] {uniqueMethod},
factory.getSkipNameValidationForTesting(),
getChecksumSupplier(uniqueMethod, appView));
- appView.appInfo().addSynthesizedClass(newClass);
- builder.addSynthesizedClass(newClass, addToMainDexList);
+ appView.appInfo().addSynthesizedClass(newClass, addToMainDexClasses);
+ builder.addSynthesizedClass(newClass);
return newClass;
}
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
index 23a6465..7936ffd 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/DesugaredLibraryWrapperSynthesizer.java
@@ -525,8 +525,8 @@
Collection<DexProgramClass> wrappers)
throws ExecutionException {
for (DexProgramClass wrapper : wrappers) {
- builder.addSynthesizedClass(wrapper, false);
- appView.appInfo().addSynthesizedClass(wrapper);
+ builder.addSynthesizedClass(wrapper);
+ appView.appInfo().addSynthesizedClass(wrapper, false);
}
irConverter.optimizeSynthesizedClasses(wrappers, executorService);
}
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 6f46dc6..aa15050 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
@@ -41,6 +41,7 @@
import com.android.tools.r8.origin.Origin;
import com.android.tools.r8.origin.SynthesizedOrigin;
import com.android.tools.r8.position.MethodPosition;
+import com.android.tools.r8.shaking.MainDexClasses;
import com.android.tools.r8.utils.DescriptorUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.IterableUtils;
@@ -532,17 +533,21 @@
private void generateEmulateInterfaceLibrary(Builder<?> builder) {
// Emulated library interfaces should generate the Emulated Library EL dispatch class.
Map<DexType, List<DexType>> emulatedInterfacesHierarchy = processEmulatedInterfaceHierarchy();
+ AppInfo appInfo = appView.appInfo();
+ MainDexClasses mainDexClasses = appInfo.getMainDexClasses();
for (DexType interfaceType : emulatedInterfaces.keySet()) {
- DexClass theInterface = appView.definitionFor(interfaceType);
+ DexClass theInterface = appInfo.definitionFor(interfaceType);
if (theInterface == null) {
warnMissingEmulatedInterface(interfaceType);
} else if (theInterface.isProgramClass()) {
+ DexProgramClass theProgramInterface = theInterface.asProgramClass();
DexProgramClass synthesizedClass =
synthesizeEmulateInterfaceLibraryClass(
- theInterface.asProgramClass(), emulatedInterfacesHierarchy);
+ theProgramInterface, emulatedInterfacesHierarchy);
if (synthesizedClass != null) {
- builder.addSynthesizedClass(synthesizedClass, isInMainDexList(interfaceType));
- appView.appInfo().addSynthesizedClass(synthesizedClass);
+ builder.addSynthesizedClass(synthesizedClass);
+ appInfo.addSynthesizedClass(
+ synthesizedClass, mainDexClasses.contains(theProgramInterface));
}
}
}
@@ -797,10 +802,6 @@
return factory.createType(interfaceTypeDescriptor);
}
- private boolean isInMainDexList(DexType iface) {
- return appView.appInfo().isInMainDexList(iface);
- }
-
// Represent a static interface method as a method of companion class.
final DexMethod staticAsMethodOfCompanionClass(DexMethod method) {
// No changes for static methods.
@@ -1000,13 +1001,18 @@
// make original default methods abstract, remove bridge methods, create dispatch
// classes if needed.
AppInfo appInfo = appView.appInfo();
- for (Entry<DexType, DexProgramClass> entry : processInterfaces(builder, flavour).entrySet()) {
- // Don't need to optimize synthesized class since all of its methods
- // are just moved from interfaces and don't need to be re-processed.
- DexProgramClass synthesizedClass = entry.getValue();
- builder.addSynthesizedClass(synthesizedClass, isInMainDexList(entry.getKey()));
- appInfo.addSynthesizedClass(synthesizedClass);
- }
+ MainDexClasses mainDexClasses = appInfo.getMainDexClasses();
+ processInterfaces(builder, flavour)
+ .forEach(
+ (interfaceClass, synthesizedClass) -> {
+ // Don't need to optimize synthesized class since all of its methods
+ // are just moved from interfaces and don't need to be re-processed.
+ builder.addSynthesizedClass(synthesizedClass);
+ boolean addToMainDexClasses =
+ interfaceClass.isProgramClass()
+ && mainDexClasses.contains(interfaceClass.asProgramClass());
+ appInfo.addSynthesizedClass(synthesizedClass, addToMainDexClasses);
+ });
if (appView.options().isDesugaredLibraryCompilation()) {
renameEmulatedInterfaces();
@@ -1030,7 +1036,7 @@
&& clazz.isInterface() == mustBeInterface;
}
- private Map<DexType, DexProgramClass> processInterfaces(Builder<?> builder, Flavor flavour) {
+ private Map<DexClass, DexProgramClass> processInterfaces(Builder<?> builder, Flavor flavour) {
InterfaceProcessorNestedGraphLens.Builder graphLensBuilder =
InterfaceProcessorNestedGraphLens.builder();
InterfaceProcessor processor = new InterfaceProcessor(appView, this);
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
index 6864127..a792f06 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/InterfaceProcessor.java
@@ -59,7 +59,7 @@
private final InterfaceMethodRewriter rewriter;
// All created companion and dispatch classes indexed by interface type.
- final Map<DexType, DexProgramClass> syntheticClasses = new IdentityHashMap<>();
+ final Map<DexClass, DexProgramClass> syntheticClasses = new IdentityHashMap<>();
InterfaceProcessor(
AppView<?> appView, InterfaceMethodRewriter rewriter) {
@@ -221,7 +221,7 @@
rewriter.factory.getSkipNameValidationForTesting(),
getChecksumSupplier(iface),
Collections.singletonList(iface));
- syntheticClasses.put(iface.type, companionClass);
+ syntheticClasses.put(iface, companionClass);
}
private ChecksumSupplier getChecksumSupplier(DexProgramClass iface) {
@@ -307,7 +307,7 @@
rewriter.factory.getSkipNameValidationForTesting(),
DexProgramClass::checksumFromType,
callers);
- syntheticClasses.put(iface.type, dispatchClass);
+ syntheticClasses.put(iface, dispatchClass);
return dispatchClass;
}
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 8deb4fc..104fc97 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
@@ -167,7 +167,7 @@
synthesizeVirtualMethods(mainMethod),
appView.dexItemFactory().getSkipNameValidationForTesting(),
LambdaClass::computeChecksumForSynthesizedClass);
- appView.appInfo().addSynthesizedClass(clazz);
+ appView.appInfo().addSynthesizedClass(clazz, false);
// The method addSynthesizedFrom() may be called concurrently. To avoid a Concurrent-
// ModificationException we must use synchronization.
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 c4709c7..dd7889d 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
@@ -157,8 +157,8 @@
knownLambdaClasses.values(), converter, executorService);
for (LambdaClass lambdaClass : knownLambdaClasses.values()) {
DexProgramClass synthesizedClass = lambdaClass.getOrCreateLambdaClass();
- appView.appInfo().addSynthesizedClass(synthesizedClass);
- builder.addSynthesizedClass(synthesizedClass, lambdaClass.addToMainDexList.get());
+ appView.appInfo().addSynthesizedClass(synthesizedClass, lambdaClass.addToMainDexList.get());
+ builder.addSynthesizedClass(synthesizedClass);
}
optimizeSynthesizedClasses(converter, executorService);
}
@@ -190,10 +190,6 @@
LambdaDescriptor.infer(callSite, appView.appInfoForDesugaring(), context));
}
- private boolean isInMainDexList(DexType type) {
- return appView.appInfo().isInMainDexList(type);
- }
-
// Returns a lambda class corresponding to the lambda descriptor and context,
// creates the class if it does not yet exist.
public LambdaClass getOrCreateLambdaClass(
@@ -224,7 +220,7 @@
}
}
lambdaClass.addSynthesizedFrom(accessedFrom.getHolder());
- if (isInMainDexList(accessedFrom.getHolderType())) {
+ if (appView.appInfo().getMainDexClasses().contains(accessedFrom.getHolder())) {
lambdaClass.addToMainDexList.set(true);
}
return lambdaClass;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
index 67571b3..8370326 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/NestBasedAccessDesugaring.java
@@ -196,15 +196,11 @@
void synthesizeNestConstructor(DexApplication.Builder<?> builder) {
if (nestConstructorUsed) {
- appView.appInfo().addSynthesizedClass(nestConstructor);
- builder.addSynthesizedClass(nestConstructor, true);
+ appView.appInfo().addSynthesizedClass(nestConstructor, true);
+ builder.addSynthesizedClass(nestConstructor);
}
}
- public static boolean isNestConstructor(DexType type) {
- return type.getName().equals(NEST_CONSTRUCTOR_NAME);
- }
-
private DexString computeMethodBridgeName(DexEncodedMethod method) {
String methodName = method.method.name.toString();
String fullName;
diff --git a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
index 4043023..613fac6 100644
--- a/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
+++ b/src/main/java/com/android/tools/r8/ir/desugar/TwrCloseResourceRewriter.java
@@ -28,6 +28,7 @@
import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.desugar.backports.BackportedMethods;
import com.android.tools.r8.origin.SynthesizedOrigin;
+import com.android.tools.r8.shaking.MainDexClasses;
import com.android.tools.r8.utils.InternalOptions;
import com.google.common.collect.Sets;
import java.util.Collections;
@@ -161,10 +162,10 @@
// Process created class and method.
AppInfo appInfo = appView.appInfo();
- boolean addToMainDexList =
- referencingClasses.stream().anyMatch(clazz -> appInfo.isInMainDexList(clazz.type));
- appInfo.addSynthesizedClass(utilityClass);
+ MainDexClasses mainDexClasses = appInfo.getMainDexClasses();
+ boolean addToMainDexList = mainDexClasses.containsAnyOf(referencingClasses);
+ appInfo.addSynthesizedClass(utilityClass, addToMainDexList);
converter.optimizeSynthesizedClass(utilityClass, executorService);
- builder.addSynthesizedClass(utilityClass, addToMainDexList);
+ builder.addSynthesizedClass(utilityClass);
}
}
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 fc01ffe..611a249 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
@@ -61,7 +61,7 @@
import com.android.tools.r8.ir.optimize.lambda.LambdaMerger;
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
-import com.android.tools.r8.shaking.MainDexClasses;
+import com.android.tools.r8.shaking.MainDexTracingResult;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.IteratorUtils;
import com.android.tools.r8.utils.ListUtils;
@@ -88,7 +88,7 @@
private final Set<DexMethod> blacklist;
private final LambdaMerger lambdaMerger;
private final LensCodeRewriter lensCodeRewriter;
- final MainDexClasses mainDexClasses;
+ final MainDexTracingResult mainDexClasses;
// State for inlining methods which are known to be called twice.
private boolean applyDoubleInlining = false;
@@ -101,7 +101,7 @@
public Inliner(
AppView<AppInfoWithLiveness> appView,
- MainDexClasses mainDexClasses,
+ MainDexTracingResult mainDexClasses,
LambdaMerger lambdaMerger,
LensCodeRewriter lensCodeRewriter) {
Kotlin.Intrinsics intrinsics = appView.dexItemFactory().kotlin.intrinsics;
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 3d7d397..54b7f8d 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
@@ -108,7 +108,7 @@
private final Map<DexType, ProgramMethodSet> enumsUnboxingCandidates;
private final Map<DexType, Set<DexField>> requiredEnumInstanceFieldData =
new ConcurrentHashMap<>();
- private final Set<DexType> enumsToUnboxWithPackageRequirement = Sets.newIdentityHashSet();
+ private final Set<DexProgramClass> enumsToUnboxWithPackageRequirement = Sets.newIdentityHashSet();
private EnumUnboxingRewriter enumUnboxerRewriter;
@@ -440,17 +440,17 @@
}
Map<DexType, DexType> newMethodLocationMap = new IdentityHashMap<>();
Map<String, DexProgramClass> packageToClassMap = new HashMap<>();
- for (DexType toUnbox : enumsToUnboxWithPackageRequirement) {
- String packageDescriptor = toUnbox.getPackageDescriptor();
+ 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().isInMainDexList(toUnbox)) {
- appBuilder.addToMainDexList(syntheticClass.type);
+ if (appView.appInfo().getMainDexClasses().contains(toUnbox)) {
+ appView.appInfo().getMainDexClasses().add(syntheticClass);
}
- newMethodLocationMap.put(toUnbox, syntheticClass.type);
+ newMethodLocationMap.put(toUnbox.getType(), syntheticClass.getType());
}
enumsToUnboxWithPackageRequirement.clear();
return newMethodLocationMap;
@@ -488,8 +488,8 @@
DexEncodedMethod.EMPTY_ARRAY,
factory.getSkipNameValidationForTesting(),
DexProgramClass::checksumFromType);
- appBuilder.addSynthesizedClass(syntheticClass, false);
- appView.appInfo().addSynthesizedClass(syntheticClass);
+ appBuilder.addSynthesizedClass(syntheticClass);
+ appView.appInfo().addSynthesizedClass(syntheticClass, false);
return syntheticClass;
}
@@ -559,7 +559,7 @@
if (classConstraint == Constraint.NEVER) {
markEnumAsUnboxable(Reason.ACCESSIBILITY, enumClass);
} else if (classConstraint == Constraint.PACKAGE) {
- enumsToUnboxWithPackageRequirement.add(toUnbox);
+ enumsToUnboxWithPackageRequirement.add(enumClass);
}
}
}
@@ -877,6 +877,10 @@
if (singleTarget == factory.javaLangSystemMethods.identityHashCode) {
return Reason.ELIGIBLE;
}
+ if (singleTarget == factory.stringMembers.valueOf) {
+ requiredEnumInstanceFieldData(enumClass.type, factory.enumMembers.nameField);
+ return Reason.ELIGIBLE;
+ }
if (singleTarget == factory.objectMembers.getClass
&& (!invokeMethod.hasOutValue() || !invokeMethod.outValue().hasAnyUsers())) {
// This is a hidden null check.
@@ -1238,9 +1242,7 @@
});
clazz.getMethodCollection().removeMethods(methodsToRemove);
} else {
- clazz
- .getMethodCollection()
- .replaceMethods(encodedMethod -> fixupEncodedMethod(encodedMethod));
+ clazz.getMethodCollection().replaceMethods(this::fixupEncodedMethod);
fixupFields(clazz.staticFields(), clazz::setStaticField);
fixupFields(clazz.instanceFields(), clazz::setInstanceField);
}
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 ca106ab..6c73aef 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
@@ -29,6 +29,7 @@
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;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
import com.android.tools.r8.ir.code.ArrayAccess;
import com.android.tools.r8.ir.code.ConstNumber;
import com.android.tools.r8.ir.code.IRCode;
@@ -205,15 +206,26 @@
continue;
}
} else if (invokedMethod == factory.javaLangSystemMethods.identityHashCode) {
- assert invokeStatic.inValues().size() == 1;
+ assert invokeStatic.arguments().size() == 1;
Value argument = invokeStatic.getArgument(0);
DexType enumType = getEnumTypeOrNull(argument, convertedEnums);
if (enumType != null) {
invokeStatic.outValue().replaceUsers(argument);
iterator.removeOrReplaceByDebugLocalRead();
}
+ } else if (invokedMethod == factory.stringMembers.valueOf) {
+ assert invokeStatic.arguments().size() == 1;
+ Value argument = invokeStatic.getArgument(0);
+ DexType enumType = getEnumTypeOrNull(argument, convertedEnums);
+ if (enumType != null) {
+ DexMethod stringValueOfMethod = computeStringValueOfUtilityMethod(enumType);
+ iterator.replaceCurrentInstruction(
+ new InvokeStatic(
+ stringValueOfMethod, invokeStatic.outValue(), invokeStatic.arguments()));
+ continue;
+ }
} else if (invokedMethod == factory.objectsMethods.requireNonNull) {
- assert invokeStatic.inValues().size() == 1;
+ assert invokeStatic.arguments().size() == 1;
Value argument = invokeStatic.getArgument(0);
DexType enumType = getEnumTypeOrNull(argument, convertedEnums);
if (enumType != null) {
@@ -221,7 +233,7 @@
iterator, invokeStatic, zeroCheckMethod, m -> synthesizeZeroCheckMethod());
}
} else if (invokedMethod == factory.objectsMethods.requireNonNullWithMessage) {
- assert invokeStatic.inValues().size() == 2;
+ assert invokeStatic.arguments().size() == 2;
Value argument = invokeStatic.getArgument(0);
DexType enumType = getEnumTypeOrNull(argument, convertedEnums);
if (enumType != null) {
@@ -407,7 +419,24 @@
factory.createProto(field.type, factory.intType),
methodName);
utilityMethods.computeIfAbsent(
- fieldMethod, m -> synthesizeInstanceFieldMethod(m, enumType, field));
+ fieldMethod, m -> synthesizeInstanceFieldMethod(m, enumType, field, null));
+ return fieldMethod;
+ }
+
+ private DexMethod computeStringValueOfUtilityMethod(DexType enumType) {
+ // TODO(b/167994636): remove duplication between instance field name read and this method.
+ assert enumsToUnbox.containsEnum(enumType);
+ String methodName = "string$valueOf$" + compatibleName(enumType);
+ DexMethod fieldMethod =
+ factory.createMethod(
+ factory.enumUnboxingUtilityType,
+ factory.createProto(factory.stringType, factory.intType),
+ methodName);
+ AbstractValue nullString =
+ appView.abstractValueFactory().createSingleStringValue(factory.createString("null"));
+ utilityMethods.computeIfAbsent(
+ fieldMethod,
+ m -> synthesizeInstanceFieldMethod(m, enumType, factory.enumMembers.nameField, nullString));
return fieldMethod;
}
@@ -458,9 +487,6 @@
utilityClass.appendStaticFields(fields);
utilityClass.addDirectMethods(requiredMethods);
assert requiredMethods.stream().allMatch(DexEncodedMethod::isPublic);
- if (utilityClassInMainDexList()) {
- builder.addToMainDexList(Collections.singletonList(utilityClass.type));
- }
// TODO(b/147860220): Use processMethodsConcurrently on requiredMethods instead.
converter.optimizeSynthesizedClass(utilityClass, executorService);
}
@@ -489,7 +515,7 @@
}
private DexEncodedMethod synthesizeInstanceFieldMethod(
- DexMethod method, DexType enumType, DexField field) {
+ DexMethod method, DexType enumType, DexField field, AbstractValue nullValue) {
assert method.proto.returnType == field.type;
assert unboxedEnumsInstanceFieldData.getInstanceFieldData(enumType, field).isMapping();
CfCode cfCode =
@@ -500,7 +526,8 @@
enumsToUnbox.getEnumValueInfoMap(enumType),
unboxedEnumsInstanceFieldData
.getInstanceFieldData(enumType, field)
- .asEnumFieldMappingData())
+ .asEnumFieldMappingData(),
+ nullValue)
.generateCfCode();
return synthesizeUtilityMethod(cfCode, method, false);
}
@@ -523,16 +550,6 @@
return synthesizeUtilityMethod(cfCode, method, false);
}
- // TODO(b/150178516): Add a test for this case.
- private boolean utilityClassInMainDexList() {
- for (DexType toUnbox : enumsToUnbox.enumSet()) {
- if (appView.appInfo().isInMainDexList(toUnbox)) {
- return true;
- }
- }
- return false;
- }
-
private DexEncodedMethod synthesizeZeroCheckMethod() {
CfCode cfCode =
EnumUnboxingCfMethods.EnumUnboxingMethods_zeroCheck(appView.options(), zeroCheckMethod);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
index b189a57..9125b1c 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/MethodOptimizationInfoCollector.java
@@ -82,6 +82,7 @@
import com.android.tools.r8.ir.code.NewInstance;
import com.android.tools.r8.ir.code.Return;
import com.android.tools.r8.ir.code.Value;
+import com.android.tools.r8.ir.conversion.IRConverter;
import com.android.tools.r8.ir.optimize.DynamicTypeOptimization;
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo;
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerReceiverAnalysis;
@@ -92,6 +93,7 @@
import com.android.tools.r8.ir.optimize.info.initializer.DefaultInstanceInitializerInfo;
import com.android.tools.r8.ir.optimize.info.initializer.InstanceInitializerInfo;
import com.android.tools.r8.ir.optimize.info.initializer.NonTrivialInstanceInitializerInfo;
+import com.android.tools.r8.ir.optimize.typechecks.CheckCastAndInstanceOfMethodSpecialization;
import com.android.tools.r8.kotlin.Kotlin;
import com.android.tools.r8.shaking.AppInfoWithLiveness;
import com.android.tools.r8.utils.InternalOptions;
@@ -112,37 +114,46 @@
import java.util.function.Predicate;
public class MethodOptimizationInfoCollector {
- private final AppView<AppInfoWithLiveness> appView;
- private final InternalOptions options;
- private final DexItemFactory dexItemFactory;
- public MethodOptimizationInfoCollector(AppView<AppInfoWithLiveness> appView) {
+ private final AppView<AppInfoWithLiveness> appView;
+ private final CheckCastAndInstanceOfMethodSpecialization
+ checkCastAndInstanceOfMethodSpecialization;
+ private final DexItemFactory dexItemFactory;
+ private final InternalOptions options;
+
+ public MethodOptimizationInfoCollector(
+ AppView<AppInfoWithLiveness> appView, IRConverter converter) {
this.appView = appView;
- this.options = appView.options();
+ this.checkCastAndInstanceOfMethodSpecialization =
+ appView.options().isRelease()
+ ? new CheckCastAndInstanceOfMethodSpecialization(appView, converter)
+ : null;
this.dexItemFactory = appView.dexItemFactory();
+ this.options = appView.options();
}
public void collectMethodOptimizationInfo(
- DexEncodedMethod method,
+ ProgramMethod method,
IRCode code,
OptimizationFeedback feedback,
DynamicTypeOptimization dynamicTypeOptimization,
InstanceFieldInitializationInfoCollection instanceFieldInitializationInfos,
Timing timing) {
- identifyBridgeInfo(method, code, feedback, timing);
+ DexEncodedMethod definition = method.getDefinition();
+ identifyBridgeInfo(definition, code, feedback, timing);
identifyClassInlinerEligibility(code, feedback, timing);
- identifyParameterUsages(method, code, feedback, timing);
- identifyReturnsArgument(code, feedback, timing);
+ identifyParameterUsages(definition, code, feedback, timing);
+ analyzeReturns(code, feedback, timing);
if (options.enableInlining) {
- identifyInvokeSemanticsForInlining(method, code, feedback, timing);
+ identifyInvokeSemanticsForInlining(definition, code, feedback, timing);
}
- computeDynamicReturnType(dynamicTypeOptimization, feedback, method, code, timing);
- computeInitializedClassesOnNormalExit(feedback, method, code, timing);
+ computeDynamicReturnType(dynamicTypeOptimization, feedback, definition, code, timing);
+ computeInitializedClassesOnNormalExit(feedback, definition, code, timing);
computeInstanceInitializerInfo(
- method, code, feedback, instanceFieldInitializationInfos, timing);
- computeMayHaveSideEffects(feedback, method, code, timing);
- computeReturnValueOnlyDependsOnArguments(feedback, method, code, timing);
- computeNonNullParamOrThrow(feedback, method, code, timing);
+ definition, code, feedback, instanceFieldInitializationInfos, timing);
+ computeMayHaveSideEffects(feedback, definition, code, timing);
+ computeReturnValueOnlyDependsOnArguments(feedback, definition, code, timing);
+ computeNonNullParamOrThrow(feedback, definition, code, timing);
computeNonNullParamOnNormalExits(feedback, code, timing);
}
@@ -345,13 +356,13 @@
return builder.build();
}
- private void identifyReturnsArgument(IRCode code, OptimizationFeedback feedback, Timing timing) {
+ private void analyzeReturns(IRCode code, OptimizationFeedback feedback, Timing timing) {
timing.begin("Identify returns argument");
- identifyReturnsArgument(code, feedback);
+ analyzeReturns(code, feedback);
timing.end();
}
- private void identifyReturnsArgument(IRCode code, OptimizationFeedback feedback) {
+ private void analyzeReturns(IRCode code, OptimizationFeedback feedback) {
ProgramMethod context = code.context();
DexEncodedMethod method = context.getDefinition();
List<BasicBlock> normalExits = code.computeNormalExitBlocks();
@@ -381,6 +392,10 @@
AbstractValue abstractReturnValue = definition.getAbstractValue(appView, context);
if (abstractReturnValue.isNonTrivial()) {
feedback.methodReturnsAbstractValue(method, appView, abstractReturnValue);
+ if (checkCastAndInstanceOfMethodSpecialization != null) {
+ checkCastAndInstanceOfMethodSpecialization.addCandidateForOptimization(
+ context, abstractReturnValue);
+ }
}
}
}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
index d9db007..07b7ce1 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackDelayed.java
@@ -189,6 +189,11 @@
}
@Override
+ public synchronized void unsetAbstractReturnValue(DexEncodedMethod method) {
+ getMethodOptimizationInfoForUpdating(method).unsetAbstractReturnValue();
+ }
+
+ @Override
public synchronized void methodReturnsObjectWithUpperBoundType(
DexEncodedMethod method, AppView<?> appView, TypeElement type) {
getMethodOptimizationInfoForUpdating(method).markReturnsObjectWithUpperBoundType(appView, type);
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
index 49ffaf9..6a28331 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackIgnore.java
@@ -76,6 +76,9 @@
DexEncodedMethod method, AppView<AppInfoWithLiveness> appView, AbstractValue value) {}
@Override
+ public void unsetAbstractReturnValue(DexEncodedMethod method) {}
+
+ @Override
public void methodReturnsObjectWithUpperBoundType(
DexEncodedMethod method, AppView<?> appView, TypeElement type) {}
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
index 62edebf..9a3bb51 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/OptimizationFeedbackSimple.java
@@ -98,7 +98,12 @@
@Override
public void methodReturnsAbstractValue(
DexEncodedMethod method, AppView<AppInfoWithLiveness> appView, AbstractValue value) {
- // Ignored.
+ method.getMutableOptimizationInfo().markReturnsAbstractValue(value);
+ }
+
+ @Override
+ public void unsetAbstractReturnValue(DexEncodedMethod method) {
+ method.getMutableOptimizationInfo().unsetAbstractReturnValue();
}
@Override
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
index 610bad0..6d9fc9f 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/info/UpdatableMethodOptimizationInfo.java
@@ -11,6 +11,7 @@
import com.android.tools.r8.ir.analysis.type.ClassTypeElement;
import com.android.tools.r8.ir.analysis.type.TypeElement;
import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.analysis.value.UnknownValue;
import com.android.tools.r8.ir.optimize.classinliner.ClassInlinerEligibilityInfo;
import com.android.tools.r8.ir.optimize.info.ParameterUsagesInfo.ParameterUsage;
import com.android.tools.r8.ir.optimize.info.bridge.BridgeInfo;
@@ -406,6 +407,10 @@
abstractReturnValue = value;
}
+ void unsetAbstractReturnValue() {
+ abstractReturnValue = UnknownValue.getInstance();
+ }
+
void markReturnsObjectWithUpperBoundType(AppView<?> appView, TypeElement type) {
assert type != null;
// We may get more precise type information if the method is reprocessed (e.g., due to
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
index b80283b..0f6a8ed 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/lambda/LambdaGroup.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.ir.optimize.info.OptimizationFeedback;
import com.android.tools.r8.ir.optimize.lambda.CodeProcessor.Strategy;
import com.android.tools.r8.kotlin.Kotlin;
+import com.android.tools.r8.shaking.MainDexClasses;
import com.android.tools.r8.utils.ThrowingConsumer;
import com.google.common.collect.Lists;
import com.google.common.io.BaseEncoding;
@@ -58,6 +59,10 @@
this.id = id;
this.clazz = clazz;
}
+
+ public DexProgramClass getLambdaClass() {
+ return clazz;
+ }
}
public LambdaGroup(LambdaGroupId id) {
@@ -93,8 +98,9 @@
final boolean shouldAddToMainDex(AppView<?> appView) {
// We add the group class to main index if any of the
// lambda classes it replaces is added to main index.
- for (DexType type : lambdas.keySet()) {
- if (appView.appInfo().isInMainDexList(type)) {
+ MainDexClasses mainDexClasses = appView.appInfo().getMainDexClasses();
+ for (LambdaInfo info : lambdas.values()) {
+ if (mainDexClasses.contains(info.getLambdaClass())) {
return true;
}
}
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 a716bd4..a7b1576 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
@@ -367,8 +367,10 @@
// Add synthesized lambda group classes to the builder.
for (Entry<LambdaGroup, DexProgramClass> entry : lambdaGroupsClasses.entrySet()) {
DexProgramClass synthesizedClass = entry.getValue();
- appView.appInfo().addSynthesizedClass(synthesizedClass);
- builder.addSynthesizedClass(synthesizedClass, entry.getKey().shouldAddToMainDex(appView));
+ appView
+ .appInfo()
+ .addSynthesizedClass(synthesizedClass, entry.getKey().shouldAddToMainDex(appView));
+ builder.addSynthesizedClass(synthesizedClass);
// Eventually, we need to process synthesized methods in the lambda group.
// Otherwise, abstract SynthesizedCode will be flown to Enqueuer.
// But that process should not see the holder. Otherwise, lambda calls in the main dispatch
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
index 6ad81c8..06a3b1a 100644
--- a/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
+++ b/src/main/java/com/android/tools/r8/ir/optimize/staticizer/StaticizingProcessor.java
@@ -402,7 +402,7 @@
OptimizationFeedback feedback) {
return (code, methodProcessor) ->
converter.collectOptimizationInfo(
- code.method(),
+ code.context(),
code,
ClassInitializerDefaultsResult.empty(),
feedback,
diff --git a/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
new file mode 100644
index 0000000..a8f3018
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/ir/optimize/typechecks/CheckCastAndInstanceOfMethodSpecialization.java
@@ -0,0 +1,164 @@
+// 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.typechecks;
+
+import static com.android.tools.r8.graph.AccessControl.isClassAccessible;
+import static com.android.tools.r8.graph.DexProgramClass.asProgramClassOrNull;
+
+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.ProgramMethod;
+import com.android.tools.r8.graph.ResolutionResult.SingleResolutionResult;
+import com.android.tools.r8.ir.analysis.value.AbstractValue;
+import com.android.tools.r8.ir.code.IRCode;
+import com.android.tools.r8.ir.conversion.IRConverter;
+import com.android.tools.r8.ir.optimize.info.MethodOptimizationInfo;
+import com.android.tools.r8.ir.optimize.info.OptimizationFeedbackSimple;
+import com.android.tools.r8.shaking.AppInfoWithLiveness;
+import com.android.tools.r8.utils.Action;
+import com.android.tools.r8.utils.collections.ProgramMethodSet;
+
+/**
+ * An optimization that merges a method override (B.m()) into the method it overrides (A.m()).
+ *
+ * <p>If the method and its override effectively implement an 'instanceof B' instruction, i.e.,
+ * A.m() returns false and B.m() returns true, then B.m() is removed and the body of A.m() is
+ * updated to {@code return this instanceof B}.
+ *
+ * <p>If the method and its override implement 'not instanceof B', then B.m() is removed and the
+ * body of A.m() is updated to {@code return !(this instance B)}.
+ *
+ * <p>TODO(b/151596599): Also handle methods that implement casts.
+ */
+public class CheckCastAndInstanceOfMethodSpecialization implements Action {
+
+ private static final OptimizationFeedbackSimple feedback =
+ OptimizationFeedbackSimple.getInstance();
+
+ private final AppView<AppInfoWithLiveness> appView;
+ private final IRConverter converter;
+
+ private final ProgramMethodSet candidatesForInstanceOfOptimization =
+ ProgramMethodSet.createSorted();
+
+ public CheckCastAndInstanceOfMethodSpecialization(
+ AppView<AppInfoWithLiveness> appView, IRConverter converter) {
+ assert !appView.options().debug;
+ this.appView = appView;
+ this.converter = converter;
+ }
+
+ public void addCandidateForOptimization(ProgramMethod method, AbstractValue abstractReturnValue) {
+ if (!converter.isInWave()) {
+ return;
+ }
+ if (isCandidateForInstanceOfOptimization(method, abstractReturnValue)) {
+ synchronized (this) {
+ if (candidatesForInstanceOfOptimization.isEmpty()) {
+ converter.addWaveDoneAction(this);
+ }
+ candidatesForInstanceOfOptimization.add(method);
+ }
+ }
+ }
+
+ private boolean isCandidateForInstanceOfOptimization(
+ ProgramMethod method, AbstractValue abstractReturnValue) {
+ return method.getReference().getReturnType().isBooleanType()
+ && abstractReturnValue.isSingleBoolean();
+ }
+
+ @Override
+ public void execute() {
+ assert !candidatesForInstanceOfOptimization.isEmpty();
+ ProgramMethodSet processed = ProgramMethodSet.create();
+ for (ProgramMethod method : candidatesForInstanceOfOptimization) {
+ if (!processed.contains(method)) {
+ processCandidateForInstanceOfOptimization(method);
+ }
+ }
+ }
+
+ private void processCandidateForInstanceOfOptimization(ProgramMethod method) {
+ DexEncodedMethod definition = method.getDefinition();
+ if (!definition.isNonPrivateVirtualMethod()) {
+ return;
+ }
+
+ MethodOptimizationInfo optimizationInfo = method.getDefinition().getOptimizationInfo();
+ if (optimizationInfo.mayHaveSideEffects()) {
+ return;
+ }
+
+ AbstractValue abstractReturnValue = optimizationInfo.getAbstractReturnValue();
+ if (!abstractReturnValue.isSingleBoolean()) {
+ return;
+ }
+
+ ProgramMethod parentMethod = resolveOnSuperClass(method);
+ if (parentMethod == null || !parentMethod.getDefinition().isNonPrivateVirtualMethod()) {
+ return;
+ }
+
+ MethodOptimizationInfo parentOptimizationInfo =
+ parentMethod.getDefinition().getOptimizationInfo();
+ if (parentOptimizationInfo.mayHaveSideEffects()) {
+ return;
+ }
+
+ AbstractValue abstractParentReturnValue = parentOptimizationInfo.getAbstractReturnValue();
+ if (!abstractParentReturnValue.isSingleBoolean()) {
+ return;
+ }
+
+ // Verify that the methods are not pinned. They shouldn't be, since we've computed an abstract
+ // return value for both.
+ assert !appView.appInfo().isPinned(method.getReference());
+ assert !appView.appInfo().isPinned(parentMethod.getReference());
+
+ if (appView
+ .appInfo()
+ .getObjectAllocationInfoCollection()
+ .hasInstantiatedStrictSubtype(method.getHolder())) {
+ return;
+ }
+
+ DexEncodedMethod parentMethodDefinition = parentMethod.getDefinition();
+ if (abstractParentReturnValue == abstractReturnValue) {
+ // The parent method is already guaranteed to return the same value.
+ } else if (isClassAccessible(method.getHolder(), parentMethod, appView).isTrue()) {
+ parentMethodDefinition.setCode(
+ parentMethodDefinition.buildInstanceOfCode(
+ method.getHolderType(), abstractParentReturnValue.isTrue(), appView.options()),
+ appView);
+ // Rebuild inlining constraints.
+ IRCode code =
+ parentMethodDefinition.getCode().buildIR(parentMethod, appView, parentMethod.getOrigin());
+ converter.markProcessed(code, feedback);
+ // Fixup method optimization info (the method no longer returns a constant).
+ feedback.unsetAbstractReturnValue(parentMethod.getDefinition());
+ } else {
+ return;
+ }
+
+ method.getHolder().removeMethod(method.getReference());
+ }
+
+ private ProgramMethod resolveOnSuperClass(ProgramMethod method) {
+ DexProgramClass superClass =
+ asProgramClassOrNull(appView.definitionFor(method.getHolder().superType));
+ if (superClass == null) {
+ return null;
+ }
+
+ SingleResolutionResult resolutionResult =
+ appView.appInfo().resolveMethodOn(superClass, method.getReference()).asSingleResolution();
+ if (resolutionResult == null) {
+ return null;
+ }
+ return resolutionResult.getResolvedProgramMethod();
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
index cb1823a..5036205 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/DesugaredLibraryAPIConversionCfCodeProvider.java
@@ -8,6 +8,8 @@
import com.android.tools.r8.cf.code.CfConstNull;
import com.android.tools.r8.cf.code.CfConstString;
import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfFrame;
+import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfInstanceOf;
import com.android.tools.r8.cf.code.CfInstruction;
@@ -30,6 +32,8 @@
import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.desugar.DesugaredLibraryAPIConverter;
+import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
+import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
@@ -234,6 +238,11 @@
DexItemFactory factory = appView.dexItemFactory();
List<CfInstruction> instructions = new ArrayList<>();
+ ImmutableInt2ReferenceSortedMap<FrameType> locals =
+ ImmutableInt2ReferenceSortedMap.<FrameType>builder()
+ .put(0, FrameType.initialized(argType))
+ .build();
+
// if (arg == null) { return null };
CfLabel nullDest = new CfLabel();
instructions.add(new CfLoad(ValueType.fromDexType(argType), 0));
@@ -241,6 +250,7 @@
instructions.add(new CfConstNull());
instructions.add(new CfReturn(ValueType.OBJECT));
instructions.add(nullDest);
+ instructions.add(new CfFrame(locals, ImmutableList.of()));
// if (arg instanceOf ReverseWrapper) { return ((ReverseWrapper) arg).wrapperField};
assert reverseWrapperField != null;
@@ -254,6 +264,7 @@
new CfFieldInstruction(Opcodes.GETFIELD, reverseWrapperField, reverseWrapperField));
instructions.add(new CfReturn(ValueType.fromDexType(reverseWrapperField.type)));
instructions.add(unwrapDest);
+ instructions.add(new CfFrame(locals, ImmutableList.of()));
// return new Wrapper(wrappedValue);
instructions.add(new CfNew(wrapperField.holder));
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EmulateInterfaceSyntheticCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EmulateInterfaceSyntheticCfCodeProvider.java
index 3cb4210..e0579ed 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EmulateInterfaceSyntheticCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EmulateInterfaceSyntheticCfCodeProvider.java
@@ -5,6 +5,8 @@
package com.android.tools.r8.ir.synthetic;
import com.android.tools.r8.cf.code.CfCheckCast;
+import com.android.tools.r8.cf.code.CfFrame;
+import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfInstanceOf;
import com.android.tools.r8.cf.code.CfInstruction;
@@ -20,6 +22,8 @@
import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.utils.Pair;
+import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
+import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
@@ -53,6 +57,15 @@
}
int nextLabel = 0;
+ ImmutableInt2ReferenceSortedMap.Builder<FrameType> localsBuilder =
+ ImmutableInt2ReferenceSortedMap.builder();
+ localsBuilder.put(0, FrameType.initialized(interfaceType));
+ int index = 1;
+ for (DexType param : libraryMethod.proto.parameters.values) {
+ localsBuilder.put(index++, FrameType.initialized(param));
+ }
+ ImmutableInt2ReferenceSortedMap<FrameType> locals = localsBuilder.build();
+
instructions.add(new CfLoad(ValueType.fromDexType(interfaceType), 0));
instructions.add(new CfInstanceOf(libraryMethod.holder));
instructions.add(new CfIf(If.Type.EQ, ValueType.INT, labels[nextLabel]));
@@ -68,6 +81,7 @@
for (Pair<DexType, DexMethod> dispatch : extraDispatchCases) {
// Type check basic block.
instructions.add(labels[nextLabel++]);
+ instructions.add(new CfFrame(locals, ImmutableList.of()));
instructions.add(new CfLoad(ValueType.fromDexType(interfaceType), 0));
instructions.add(new CfInstanceOf(dispatch.getFirst()));
instructions.add(new CfIf(If.Type.EQ, ValueType.INT, labels[nextLabel]));
@@ -82,6 +96,7 @@
// Branch with companion call.
instructions.add(labels[nextLabel]);
+ instructions.add(new CfFrame(locals, ImmutableList.of()));
instructions.add(new CfLoad(ValueType.fromDexType(interfaceType), 0));
loadExtraParameters(instructions);
instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, companionMethod, false));
diff --git a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
index 8b35793..52cdb30 100644
--- a/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
+++ b/src/main/java/com/android/tools/r8/ir/synthetic/EnumUnboxingCfCodeProvider.java
@@ -8,6 +8,8 @@
import com.android.tools.r8.cf.code.CfConstNumber;
import com.android.tools.r8.cf.code.CfConstString;
import com.android.tools.r8.cf.code.CfFieldInstruction;
+import com.android.tools.r8.cf.code.CfFrame;
+import com.android.tools.r8.cf.code.CfFrame.FrameType;
import com.android.tools.r8.cf.code.CfIf;
import com.android.tools.r8.cf.code.CfIfCmp;
import com.android.tools.r8.cf.code.CfInstruction;
@@ -31,6 +33,8 @@
import com.android.tools.r8.ir.code.If;
import com.android.tools.r8.ir.code.ValueType;
import com.android.tools.r8.ir.optimize.enums.EnumInstanceFieldData.EnumInstanceFieldMappingData;
+import com.android.tools.r8.utils.collections.ImmutableInt2ReferenceSortedMap;
+import com.google.common.collect.ImmutableList;
import java.util.ArrayList;
import java.util.List;
import org.objectweb.asm.Opcodes;
@@ -62,21 +66,26 @@
private final DexType returnType;
private final EnumValueInfoMap enumValueInfoMap;
private final EnumInstanceFieldMappingData fieldDataMap;
+ private final AbstractValue nullValue;
public EnumUnboxingInstanceFieldCfCodeProvider(
AppView<?> appView,
DexType holder,
DexType returnType,
EnumValueInfoMap enumValueInfoMap,
- EnumInstanceFieldMappingData fieldDataMap) {
+ EnumInstanceFieldMappingData fieldDataMap,
+ AbstractValue nullValue) {
super(appView, holder);
this.returnType = returnType;
this.enumValueInfoMap = enumValueInfoMap;
this.fieldDataMap = fieldDataMap;
+ this.nullValue = nullValue;
}
@Override
public CfCode generateCfCode() {
+ // TODO(b/167942775): Should use a table-switch for large enums (maybe same threshold in the
+ // rewriter of switchmaps).
// Generated static method, for class com.x.MyEnum {A(10),B(20);} would look like:
// String UtilityClass#com.x.MyEnum_toString(int i) {
// if (i == 1) { return 10;}
@@ -85,6 +94,11 @@
DexItemFactory factory = appView.dexItemFactory();
List<CfInstruction> instructions = new ArrayList<>();
+ ImmutableInt2ReferenceSortedMap<FrameType> locals =
+ ImmutableInt2ReferenceSortedMap.<FrameType>builder()
+ .put(0, FrameType.initialized(factory.intType))
+ .build();
+
// if (i == 1) { return 10;}
// if (i == 2) { return 20;}
enumValueInfoMap.forEach(
@@ -98,12 +112,19 @@
addCfInstructionsForAbstractValue(instructions, value, returnType);
instructions.add(new CfReturn(ValueType.fromDexType(returnType)));
instructions.add(dest);
+ instructions.add(new CfFrame(locals, ImmutableList.of()));
}
});
- // throw null;
- instructions.add(new CfConstNull());
- instructions.add(new CfThrow());
+ if (nullValue != null) {
+ // return "null"
+ addCfInstructionsForAbstractValue(instructions, nullValue, returnType);
+ instructions.add(new CfReturn(ValueType.fromDexType(returnType)));
+ } else {
+ // throw null;
+ instructions.add(new CfConstNull());
+ instructions.add(new CfThrow());
+ }
return standardCfCodeFromInstructions(instructions);
}
@@ -139,6 +160,11 @@
DexItemFactory factory = appView.dexItemFactory();
List<CfInstruction> instructions = new ArrayList<>();
+ ImmutableInt2ReferenceSortedMap<FrameType> locals =
+ ImmutableInt2ReferenceSortedMap.<FrameType>builder()
+ .put(0, FrameType.initialized(factory.stringType))
+ .build();
+
// if (s == null) { throw npe("Name is null"); }
CfLabel nullDest = new CfLabel();
instructions.add(new CfLoad(ValueType.fromDexType(factory.stringType), 0));
@@ -150,6 +176,7 @@
new CfInvoke(Opcodes.INVOKESPECIAL, factory.npeMethods.initWithMessage, false));
instructions.add(new CfThrow());
instructions.add(nullDest);
+ instructions.add(new CfFrame(locals, ImmutableList.of()));
// if (s.equals("A")) { return 1;}
// if (s.equals("B")) { return 2;}
@@ -165,6 +192,7 @@
instructions.add(new CfConstNumber(enumValueInfo.convertToInt(), ValueType.INT));
instructions.add(new CfReturn(ValueType.INT));
instructions.add(dest);
+ instructions.add(new CfFrame(locals, ImmutableList.of()));
});
// throw new IllegalArgumentException("No enum constant com.x.MyEnum." + s);
@@ -225,6 +253,9 @@
instructions.add(new CfInvoke(Opcodes.INVOKESTATIC, initializationMethod, false));
instructions.add(new CfFieldInstruction(Opcodes.PUTSTATIC, utilityField, utilityField));
instructions.add(nullDest);
+ instructions.add(
+ new CfFrame(
+ ImmutableInt2ReferenceSortedMap.<FrameType>builder().build(), ImmutableList.of()));
instructions.add(new CfFieldInstruction(Opcodes.GETSTATIC, utilityField, utilityField));
instructions.add(new CfReturn(ValueType.OBJECT));
return standardCfCodeFromInstructions(instructions);
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 8c895f7..ec34d75 100644
--- a/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
+++ b/src/main/java/com/android/tools/r8/jar/CfApplicationWriter.java
@@ -16,6 +16,7 @@
import com.android.tools.r8.errors.Unimplemented;
import com.android.tools.r8.errors.Unreachable;
import com.android.tools.r8.graph.AppView;
+import com.android.tools.r8.graph.CfCode;
import com.android.tools.r8.graph.DexAnnotation;
import com.android.tools.r8.graph.DexAnnotationElement;
import com.android.tools.r8.graph.DexAnnotationSet;
@@ -36,6 +37,8 @@
import com.android.tools.r8.graph.InnerClassAttribute;
import com.android.tools.r8.graph.NestMemberClassAttribute;
import com.android.tools.r8.graph.ParameterAnnotationsList;
+import com.android.tools.r8.graph.ProgramMethod;
+import com.android.tools.r8.ir.conversion.LensCodeRewriterUtils;
import com.android.tools.r8.naming.NamingLens;
import com.android.tools.r8.naming.ProguardMapSupplier;
import com.android.tools.r8.references.Reference;
@@ -108,12 +111,13 @@
}
Optional<String> markerString =
marker.isRelocator() ? Optional.empty() : Optional.of(marker.toString());
+ LensCodeRewriterUtils rewriter = new LensCodeRewriterUtils(appView);
for (DexProgramClass clazz : application.classes()) {
if (clazz.getSynthesizedFrom().isEmpty()
|| options.isDesugaredLibraryCompilation()
|| options.cfToCfDesugar) {
try {
- writeClass(clazz, consumer, markerString);
+ writeClass(clazz, consumer, rewriter, markerString);
} catch (ClassTooLargeException e) {
throw appView
.options()
@@ -145,7 +149,10 @@
}
private void writeClass(
- DexProgramClass clazz, ClassFileConsumer consumer, Optional<String> markerString) {
+ DexProgramClass clazz,
+ ClassFileConsumer consumer,
+ LensCodeRewriterUtils rewriter,
+ Optional<String> markerString) {
ClassWriter writer = new ClassWriter(0);
if (markerString.isPresent()) {
int markerStringPoolIndex = writer.newConst(markerString.get());
@@ -194,12 +201,7 @@
for (DexEncodedField field : clazz.instanceFields()) {
writeField(field, writer);
}
- for (DexEncodedMethod method : clazz.directMethods()) {
- writeMethod(method, writer, defaults, version);
- }
- for (DexEncodedMethod method : clazz.virtualMethods()) {
- writeMethod(method, writer, defaults, version);
- }
+ clazz.forEachProgramMethod(method -> writeMethod(method, version, rewriter, writer, defaults));
writer.visitEnd();
byte[] result = writer.toByteArray();
@@ -323,28 +325,30 @@
}
private void writeMethod(
- DexEncodedMethod method,
+ ProgramMethod method,
+ int classFileVersion,
+ LensCodeRewriterUtils rewriter,
ClassWriter writer,
- ImmutableMap<DexString, DexValue> defaults,
- int classFileVersion) {
- int access = method.accessFlags.getAsCfAccessFlags();
- String name = namingLens.lookupName(method.method).toString();
- String desc = method.descriptor(namingLens);
- String signature = getSignature(method.annotations());
- String[] exceptions = getExceptions(method.annotations());
+ ImmutableMap<DexString, DexValue> defaults) {
+ DexEncodedMethod definition = method.getDefinition();
+ int access = definition.getAccessFlags().getAsCfAccessFlags();
+ String name = namingLens.lookupName(method.getReference()).toString();
+ String desc = definition.descriptor(namingLens);
+ String signature = getSignature(definition.annotations());
+ String[] exceptions = getExceptions(definition.annotations());
MethodVisitor visitor = writer.visitMethod(access, name, desc, signature, exceptions);
- if (defaults.containsKey(method.method.name)) {
+ if (defaults.containsKey(definition.getName())) {
AnnotationVisitor defaultVisitor = visitor.visitAnnotationDefault();
if (defaultVisitor != null) {
- writeAnnotationElement(defaultVisitor, null, defaults.get(method.method.name));
+ writeAnnotationElement(defaultVisitor, null, defaults.get(definition.getName()));
defaultVisitor.visitEnd();
}
}
- writeMethodParametersAnnotation(visitor, method.annotations().annotations);
- writeAnnotations(visitor::visitAnnotation, method.annotations().annotations);
- writeParameterAnnotations(visitor, method.parameterAnnotationsList);
- if (!method.shouldNotHaveCode()) {
- writeCode(method, visitor, classFileVersion);
+ writeMethodParametersAnnotation(visitor, definition.annotations().annotations);
+ writeAnnotations(visitor::visitAnnotation, definition.annotations().annotations);
+ writeParameterAnnotations(visitor, definition.parameterAnnotationsList);
+ if (!definition.shouldNotHaveCode()) {
+ writeCode(method, classFileVersion, rewriter, visitor);
}
visitor.visitEnd();
}
@@ -478,8 +482,13 @@
}
}
- private void writeCode(DexEncodedMethod method, MethodVisitor visitor, int classFileVersion) {
- method.getCode().asCfCode().write(method, visitor, namingLens, appView, classFileVersion);
+ private void writeCode(
+ ProgramMethod method,
+ int classFileVersion,
+ LensCodeRewriterUtils rewriter,
+ MethodVisitor visitor) {
+ CfCode code = method.getDefinition().getCode().asCfCode();
+ code.write(method, classFileVersion, appView, namingLens, rewriter, visitor);
}
public static String printCf(byte[] result) {
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 05c6f6c..6c6bab5 100644
--- a/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
+++ b/src/main/java/com/android/tools/r8/shaking/AppInfoWithLiveness.java
@@ -28,7 +28,6 @@
import com.android.tools.r8.graph.FieldAccessInfo;
import com.android.tools.r8.graph.FieldAccessInfoCollection;
import com.android.tools.r8.graph.FieldAccessInfoCollectionImpl;
-import com.android.tools.r8.graph.FieldAccessInfoImpl;
import com.android.tools.r8.graph.FieldResolutionResult;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.GraphLens.NestedGraphLens;
@@ -118,7 +117,7 @@
* a given field is read/written by the program, and it also includes all indirect accesses to
* each field. The latter is used, for example, during member rebinding.
*/
- private final FieldAccessInfoCollectionImpl fieldAccessInfoCollection;
+ private FieldAccessInfoCollectionImpl fieldAccessInfoCollection;
/** Information about instantiated classes and their allocation sites. */
private final ObjectAllocationInfoCollectionImpl objectAllocationInfoCollection;
/** Set of all methods referenced in virtual invokes, along with calling context. */
@@ -197,6 +196,7 @@
// TODO(zerny): Clean up the constructors so we have just one.
AppInfoWithLiveness(
DirectMappedDexApplication application,
+ MainDexClasses mainDexClasses,
SyntheticItems.CommittedItems syntheticItems,
Set<DexType> deadProtoTypes,
Set<DexType> missingTypes,
@@ -238,7 +238,7 @@
EnumValueInfoMapCollection enumValueInfoMaps,
Set<DexType> constClassReferences,
Map<DexType, Visibility> initClassReferences) {
- super(application, syntheticItems);
+ super(application, mainDexClasses, syntheticItems);
this.deadProtoTypes = deadProtoTypes;
this.missingTypes = missingTypes;
this.liveTypes = liveTypes;
@@ -325,6 +325,7 @@
Map<DexType, Visibility> initClassReferences) {
super(
appInfoWithClassHierarchy.app(),
+ appInfoWithClassHierarchy.getMainDexClasses(),
appInfoWithClassHierarchy.getSyntheticItems().commit(appInfoWithClassHierarchy.app()));
this.deadProtoTypes = deadProtoTypes;
this.missingTypes = missingTypes;
@@ -420,6 +421,7 @@
Collection<DexReference> additionalPinnedItems) {
this(
application,
+ previous.getMainDexClasses(),
previous.getSyntheticItems().commit(application),
previous.deadProtoTypes,
previous.missingTypes,
@@ -507,7 +509,10 @@
AppInfoWithLiveness previous,
Map<DexField, Int2ReferenceMap<DexField>> switchMaps,
EnumValueInfoMapCollection enumValueInfoMaps) {
- super(previous.app(), previous.getSyntheticItems().commit(previous.app()));
+ super(
+ previous.app(),
+ previous.getMainDexClasses(),
+ previous.getSyntheticItems().commit(previous.app()));
this.deadProtoTypes = previous.deadProtoTypes;
this.missingTypes = previous.missingTypes;
this.liveTypes = previous.liveTypes;
@@ -715,25 +720,6 @@
return constClassReferences.contains(type);
}
- public AppInfoWithLiveness withoutStaticFieldsWrites(Set<DexField> noLongerWrittenFields) {
- assert checkIfObsolete();
- if (noLongerWrittenFields.isEmpty()) {
- return this;
- }
- AppInfoWithLiveness result = new AppInfoWithLiveness(this);
- result.fieldAccessInfoCollection.forEach(
- info -> {
- if (noLongerWrittenFields.contains(info.getField())) {
- // Note that this implicitly mutates the current AppInfoWithLiveness, since the `info`
- // instance is shared between the old and the new AppInfoWithLiveness. This should not
- // lead to any problems, though, since the new AppInfo replaces the old AppInfo (we
- // never use an obsolete AppInfo).
- info.clearWrites();
- }
- });
- return result;
- }
-
public Set<DexType> getDeadProtoTypes() {
return deadProtoTypes;
}
@@ -810,7 +796,7 @@
public boolean isFieldRead(DexEncodedField encodedField) {
assert checkIfObsolete();
DexField field = encodedField.field;
- FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field);
+ FieldAccessInfo info = getFieldAccessInfoCollection().get(field);
if (info != null && info.isRead()) {
return true;
}
@@ -834,7 +820,7 @@
public boolean isFieldWrittenByFieldPutInstruction(DexEncodedField encodedField) {
assert checkIfObsolete();
DexField field = encodedField.field;
- FieldAccessInfoImpl info = fieldAccessInfoCollection.get(field);
+ FieldAccessInfo info = getFieldAccessInfoCollection().get(field);
if (info != null && info.isWritten()) {
// The field is written directly by the program itself.
return true;
@@ -850,13 +836,13 @@
public boolean isFieldOnlyWrittenInMethod(DexEncodedField field, DexEncodedMethod method) {
assert checkIfObsolete();
assert isFieldWritten(field) : "Expected field `" + field.toSourceString() + "` to be written";
- if (!isPinned(field.field)) {
- FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(field.field);
- return fieldAccessInfo != null
- && fieldAccessInfo.isWritten()
- && !fieldAccessInfo.isWrittenOutside(method);
+ if (isPinned(field.field)) {
+ return false;
}
- return false;
+ FieldAccessInfo fieldAccessInfo = getFieldAccessInfoCollection().get(field.field);
+ return fieldAccessInfo != null
+ && fieldAccessInfo.isWritten()
+ && !fieldAccessInfo.isWrittenOutside(method);
}
public boolean isInstanceFieldWrittenOnlyInInstanceInitializers(DexEncodedField field) {
@@ -865,7 +851,7 @@
if (isPinned(field.field)) {
return false;
}
- FieldAccessInfo fieldAccessInfo = fieldAccessInfoCollection.get(field.field);
+ FieldAccessInfo fieldAccessInfo = getFieldAccessInfoCollection().get(field.field);
if (fieldAccessInfo == null || !fieldAccessInfo.isWritten()) {
return false;
}
@@ -1004,6 +990,7 @@
DexDefinitionSupplier definitionSupplier = application.getDefinitionsSupplier(committedItems);
return new AppInfoWithLiveness(
application,
+ getMainDexClasses().rewrittenWithLens(lens),
committedItems,
deadProtoTypes,
missingTypes,
@@ -1015,7 +1002,9 @@
lens.rewriteMethods(methodsTargetedByInvokeDynamic),
lens.rewriteMethods(virtualMethodsTargetedByInvokeDirect),
lens.rewriteMethods(liveMethods),
- fieldAccessInfoCollection.rewrittenWithLens(definitionSupplier, lens),
+ fieldAccessInfoCollection != null
+ ? fieldAccessInfoCollection.rewrittenWithLens(definitionSupplier, lens)
+ : null,
objectAllocationInfoCollection.rewrittenWithLens(definitionSupplier, lens),
rewriteInvokesWithContexts(virtualInvokes, lens),
rewriteInvokesWithContexts(interfaceInvokes, lens),
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 ac6bad1..d692cef 100644
--- a/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
+++ b/src/main/java/com/android/tools/r8/shaking/Enqueuer.java
@@ -2792,7 +2792,7 @@
new ArrayList<>();
// Subset of synthesized classes that need to be added to the main-dex file.
- Set<DexType> mainDexTypes = Sets.newIdentityHashSet();
+ Set<DexProgramClass> mainDexTypes = Sets.newIdentityHashSet();
boolean isEmpty() {
boolean empty =
@@ -2808,7 +2808,7 @@
assert !syntheticInstantiations.containsKey(clazz.type);
syntheticInstantiations.put(clazz.type, new Pair<>(clazz, context));
if (isMainDexClass) {
- mainDexTypes.add(clazz.type);
+ mainDexTypes.add(clazz);
}
}
@@ -2836,7 +2836,11 @@
appBuilder.addProgramClass(clazzAndContext.getFirst());
}
appBuilder.addClasspathClasses(syntheticClasspathClasses.values());
- appBuilder.addToMainDexList(mainDexTypes);
+ }
+
+ void amendMainDexClasses(MainDexClasses mainDexClasses) {
+ assert !isEmpty();
+ mainDexClasses.addAll(mainDexTypes);
}
void enqueueWorkItems(Enqueuer enqueuer) {
@@ -2887,6 +2891,7 @@
additions.amendApplication(appBuilder);
return appBuilder.build();
});
+ additions.amendMainDexClasses(appInfo.getMainDexClasses());
appView.setAppInfo(appInfo);
subtypingInfo = new SubtypingInfo(appView);
@@ -3015,6 +3020,7 @@
AppInfoWithLiveness appInfoWithLiveness =
new AppInfoWithLiveness(
app,
+ appInfo.getMainDexClasses(),
appInfo.getSyntheticItems().commit(app),
deadProtoTypes,
mode.isFinalTreeShaking()
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 c21ce6c..cfadae32 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexClasses.java
@@ -1,115 +1,100 @@
-// 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.graph.AppInfo;
-import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexProgramClass;
import com.android.tools.r8.graph.DexType;
-import com.google.common.collect.ImmutableSet;
+import com.android.tools.r8.graph.GraphLens;
import com.google.common.collect.Sets;
-import java.util.Collection;
-import java.util.Collections;
import java.util.Set;
import java.util.function.Consumer;
-import java.util.function.Predicate;
public class MainDexClasses {
- public static MainDexClasses NONE = new MainDexClasses(ImmutableSet.of(), ImmutableSet.of());
+ private final Set<DexType> mainDexClasses;
- public static class Builder {
- public final AppInfo appInfo;
- public final Set<DexType> roots = Sets.newIdentityHashSet();
- public final Set<DexType> dependencies = Sets.newIdentityHashSet();
+ private MainDexClasses() {
+ this(Sets.newIdentityHashSet());
+ }
- private Builder(AppInfo appInfo) {
- this.appInfo = appInfo;
- }
+ private MainDexClasses(Set<DexType> mainDexClasses) {
+ this.mainDexClasses = mainDexClasses;
+ }
- public Builder addRoot(DexType type) {
- assert isProgramClass(type) : type.toSourceString();
- roots.add(type);
- return this;
- }
+ public static Builder builder() {
+ return new Builder();
+ }
- public Builder addRoots(Collection<DexType> rootSet) {
- assert rootSet.stream().allMatch(this::isProgramClass);
- this.roots.addAll(rootSet);
- return this;
- }
+ public static MainDexClasses createEmptyMainDexClasses() {
+ return new MainDexClasses();
+ }
- public Builder addDependency(DexType type) {
- assert isProgramClass(type);
- dependencies.add(type);
- return this;
- }
+ public void add(DexProgramClass clazz) {
+ mainDexClasses.add(clazz.getType());
+ }
- public boolean contains(DexType type) {
- return roots.contains(type) || dependencies.contains(type);
- }
+ public void addAll(MainDexClasses other) {
+ mainDexClasses.addAll(other.mainDexClasses);
+ }
- public MainDexClasses build() {
- return new MainDexClasses(roots, dependencies);
- }
+ public void addAll(MainDexTracingResult other) {
+ mainDexClasses.addAll(other.getClasses());
+ }
- private boolean isProgramClass(DexType dexType) {
- DexClass clazz = appInfo.definitionFor(dexType);
- return clazz != null && clazz.isProgramClass();
+ public void addAll(Iterable<DexProgramClass> classes) {
+ for (DexProgramClass clazz : classes) {
+ add(clazz);
}
}
- // The classes in the root set.
- private final Set<DexType> roots;
- // Additional dependencies (direct dependencies and runtime annotations with enums).
- private final Set<DexType> dependencies;
- // All main dex classes.
- private final Set<DexType> classes;
+ public boolean contains(DexProgramClass clazz) {
+ return mainDexClasses.contains(clazz.getType());
+ }
- private MainDexClasses(Set<DexType> roots, Set<DexType> dependencies) {
- assert Sets.intersection(roots, dependencies).isEmpty();
- this.roots = Collections.unmodifiableSet(roots);
- this.dependencies = Collections.unmodifiableSet(dependencies);
- this.classes = Sets.union(roots, dependencies);
+ public boolean containsAnyOf(Iterable<DexProgramClass> classes) {
+ for (DexProgramClass clazz : classes) {
+ if (contains(clazz)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public void forEach(Consumer<DexType> fn) {
+ mainDexClasses.forEach(fn);
}
public boolean isEmpty() {
- assert !roots.isEmpty() || dependencies.isEmpty();
- return roots.isEmpty();
+ return mainDexClasses.isEmpty();
}
- public Set<DexType> getRoots() {
- return roots;
+ public MainDexClasses rewrittenWithLens(GraphLens lens) {
+ MainDexClasses rewrittenMainDexClasses = createEmptyMainDexClasses();
+ for (DexType mainDexClass : mainDexClasses) {
+ DexType rewrittenMainDexClass = lens.lookupType(mainDexClass);
+ rewrittenMainDexClasses.mainDexClasses.add(rewrittenMainDexClass);
+ }
+ return rewrittenMainDexClasses;
}
- public Set<DexType> getDependencies() {
- return dependencies;
+ public int size() {
+ return mainDexClasses.size();
}
- public Set<DexType> getClasses() {
- return classes;
- }
+ public static class Builder {
- private void collectTypesMatching(
- Set<DexType> types, Predicate<DexType> predicate, Consumer<DexType> consumer) {
- types.forEach(
- type -> {
- if (predicate.test(type)) {
- consumer.accept(type);
- }
- });
- }
+ private final Set<DexType> mainDexClasses = Sets.newIdentityHashSet();
- public MainDexClasses prunedCopy(AppInfoWithLiveness appInfo) {
- Builder builder = builder(appInfo);
- Predicate<DexType> wasPruned = appInfo::wasPruned;
- collectTypesMatching(roots, wasPruned.negate(), builder::addRoot);
- collectTypesMatching(dependencies, wasPruned.negate(), builder::addDependency);
- return builder.build();
- }
+ private Builder() {}
- public static Builder builder(AppInfo appInfo) {
- return new Builder(appInfo);
+ public void add(DexProgramClass clazz) {
+ mainDexClasses.add(clazz.getType());
+ }
+
+ public MainDexClasses build() {
+ return new MainDexClasses(mainDexClasses);
+ }
}
}
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
index c122cd7..4fa5d3a 100644
--- a/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexListBuilder.java
@@ -30,7 +30,7 @@
private final Set<DexType> roots;
private final AppView<? extends AppInfoWithClassHierarchy> appView;
private final Map<DexType, Boolean> annotationTypeContainEnum;
- private final MainDexClasses.Builder mainDexClassesBuilder;
+ private final MainDexTracingResult.Builder mainDexClassesBuilder;
public static void checkForAssumedLibraryTypes(AppInfo appInfo) {
DexClass enumType = appInfo.definitionFor(appInfo.dexItemFactory().enumType);
@@ -54,7 +54,7 @@
this.appView = appView;
// Only consider program classes for the root set.
this.roots = SetUtils.mapIdentityHashSet(roots, DexProgramClass::getType);
- mainDexClassesBuilder = MainDexClasses.builder(appView.appInfo()).addRoots(this.roots);
+ mainDexClassesBuilder = MainDexTracingResult.builder(appView.appInfo()).addRoots(this.roots);
annotationTypeContainEnum = new IdentityHashMap<>();
}
@@ -62,7 +62,7 @@
return appView.appInfo();
}
- public MainDexClasses run() {
+ public MainDexTracingResult run() {
traceMainDexDirectDependencies();
traceRuntimeAnnotationsWithEnumForMainDex();
return mainDexClassesBuilder.build();
diff --git a/src/main/java/com/android/tools/r8/shaking/MainDexTracingResult.java b/src/main/java/com/android/tools/r8/shaking/MainDexTracingResult.java
new file mode 100644
index 0000000..d333211
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/shaking/MainDexTracingResult.java
@@ -0,0 +1,116 @@
+// Copyright (c) 2018, 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.graph.AppInfo;
+import com.android.tools.r8.graph.DexClass;
+import com.android.tools.r8.graph.DexType;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Set;
+import java.util.function.Consumer;
+import java.util.function.Predicate;
+
+public class MainDexTracingResult {
+
+ public static MainDexTracingResult NONE =
+ new MainDexTracingResult(ImmutableSet.of(), ImmutableSet.of());
+
+ public static class Builder {
+ public final AppInfo appInfo;
+ public final Set<DexType> roots = Sets.newIdentityHashSet();
+ public final Set<DexType> dependencies = Sets.newIdentityHashSet();
+
+ private Builder(AppInfo appInfo) {
+ this.appInfo = appInfo;
+ }
+
+ public Builder addRoot(DexType type) {
+ assert isProgramClass(type) : type.toSourceString();
+ roots.add(type);
+ return this;
+ }
+
+ public Builder addRoots(Collection<DexType> rootSet) {
+ assert rootSet.stream().allMatch(this::isProgramClass);
+ this.roots.addAll(rootSet);
+ return this;
+ }
+
+ public Builder addDependency(DexType type) {
+ assert isProgramClass(type);
+ dependencies.add(type);
+ return this;
+ }
+
+ public boolean contains(DexType type) {
+ return roots.contains(type) || dependencies.contains(type);
+ }
+
+ public MainDexTracingResult build() {
+ return new MainDexTracingResult(roots, dependencies);
+ }
+
+ private boolean isProgramClass(DexType dexType) {
+ DexClass clazz = appInfo.definitionFor(dexType);
+ return clazz != null && clazz.isProgramClass();
+ }
+ }
+
+ // The classes in the root set.
+ private final Set<DexType> roots;
+ // Additional dependencies (direct dependencies and runtime annotations with enums).
+ private final Set<DexType> dependencies;
+ // All main dex classes.
+ private final Set<DexType> classes;
+
+ private MainDexTracingResult(Set<DexType> roots, Set<DexType> dependencies) {
+ assert Sets.intersection(roots, dependencies).isEmpty();
+ this.roots = Collections.unmodifiableSet(roots);
+ this.dependencies = Collections.unmodifiableSet(dependencies);
+ this.classes = Sets.union(roots, dependencies);
+ }
+
+ public boolean isEmpty() {
+ assert !roots.isEmpty() || dependencies.isEmpty();
+ return roots.isEmpty();
+ }
+
+ public Set<DexType> getRoots() {
+ return roots;
+ }
+
+ public Set<DexType> getDependencies() {
+ return dependencies;
+ }
+
+ public Set<DexType> getClasses() {
+ return classes;
+ }
+
+ private void collectTypesMatching(
+ Set<DexType> types, Predicate<DexType> predicate, Consumer<DexType> consumer) {
+ types.forEach(
+ type -> {
+ if (predicate.test(type)) {
+ consumer.accept(type);
+ }
+ });
+ }
+
+ public MainDexTracingResult prunedCopy(AppInfoWithLiveness appInfo) {
+ Builder builder = builder(appInfo);
+ Predicate<DexType> wasPruned = appInfo::wasPruned;
+ collectTypesMatching(roots, wasPruned.negate(), builder::addRoot);
+ collectTypesMatching(dependencies, wasPruned.negate(), builder::addDependency);
+ return builder.build();
+ }
+
+ public static Builder builder(AppInfo appInfo) {
+ return new Builder(appInfo);
+ }
+}
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 1b51a73..6b5604e 100644
--- a/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
+++ b/src/main/java/com/android/tools/r8/shaking/ProguardConfigurationParser.java
@@ -51,6 +51,9 @@
private final Reporter reporter;
private final boolean allowTestOptions;
+ public static final String FLATTEN_PACKAGE_HIERARCHY = "flattenpackagehierarchy";
+ public static final String REPACKAGE_CLASSES = "repackageclasses";
+
private static final List<String> IGNORED_SINGLE_ARG_OPTIONS = ImmutableList.of(
"protomapping",
"target",
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 0d803ea..3725f5f 100644
--- a/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/StaticClassMerger.java
@@ -187,7 +187,7 @@
}
private final AppView<AppInfoWithLiveness> appView;
- private final MainDexClasses mainDexClasses;
+ private final MainDexTracingResult mainDexClasses;
/** The equivalence that should be used for the member buckets in {@link Representative}. */
private final Equivalence<DexField> fieldEquivalence;
@@ -203,7 +203,7 @@
public StaticClassMerger(
AppView<AppInfoWithLiveness> appView,
InternalOptions options,
- MainDexClasses mainDexClasses) {
+ MainDexTracingResult mainDexClasses) {
this.appView = appView;
if (options.getProguardConfiguration().isOverloadAggressively()) {
fieldEquivalence = FieldSignatureEquivalence.getEquivalenceIgnoreName();
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 17cf952..2d21927 100644
--- a/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
+++ b/src/main/java/com/android/tools/r8/shaking/VerticalClassMerger.java
@@ -217,14 +217,14 @@
// All the bridge methods that have been synthesized during vertical class merging.
private final List<SynthesizedBridgeCode> synthesizedBridges = new ArrayList<>();
- private final MainDexClasses mainDexClasses;
+ private final MainDexTracingResult mainDexClasses;
public VerticalClassMerger(
DexApplication application,
AppView<AppInfoWithLiveness> appView,
ExecutorService executorService,
Timing timing,
- MainDexClasses mainDexClasses) {
+ MainDexTracingResult mainDexClasses) {
this.application = application;
this.appInfo = appView.appInfo();
this.appView = appView;
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 7f54137..a9d5c3d 100644
--- a/src/main/java/com/android/tools/r8/utils/InternalOptions.java
+++ b/src/main/java/com/android/tools/r8/utils/InternalOptions.java
@@ -491,6 +491,10 @@
private final boolean enableTreeShaking;
private final boolean enableMinification;
+ public boolean isRelease() {
+ return !debug;
+ }
+
public boolean isShrinking() {
assert proguardConfiguration == null
|| enableTreeShaking == proguardConfiguration.isShrinking();
diff --git a/src/main/java/com/android/tools/r8/utils/MainDexList.java b/src/main/java/com/android/tools/r8/utils/MainDexListParser.java
similarity index 93%
rename from src/main/java/com/android/tools/r8/utils/MainDexList.java
rename to src/main/java/com/android/tools/r8/utils/MainDexListParser.java
index e323566..136ae2a 100644
--- a/src/main/java/com/android/tools/r8/utils/MainDexList.java
+++ b/src/main/java/com/android/tools/r8/utils/MainDexListParser.java
@@ -15,7 +15,7 @@
import com.google.common.collect.Sets;
import java.util.Set;
-public class MainDexList {
+public class MainDexListParser {
public static DexType parseEntry(String clazz, DexItemFactory itemFactory) {
if (!clazz.endsWith(CLASS_EXTENSION)) {
@@ -47,7 +47,10 @@
try {
result.add(parseEntry(line, itemFactory));
} catch (CompilationError e) {
- throw new CompilationError(e.getMessage(), e, resource.getOrigin(),
+ throw new CompilationError(
+ e.getMessage(),
+ e,
+ resource.getOrigin(),
new TextPosition(offset, lineNumber, TextPosition.UNKNOWN_COLUMN));
}
}
diff --git a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
index dd5b43a..68fa8f3 100644
--- a/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
+++ b/src/main/java/com/android/tools/r8/utils/ProgramClassCollection.java
@@ -82,7 +82,7 @@
private static DexProgramClass mergeClasses(
Reporter reporter, DexProgramClass a, DexProgramClass b) {
- if (a.type.isD8R8SynthesizedClassType()) {
+ if (a.type.isLegacySynthesizedTypeAllowedDuplication()) {
assert assertEqualClasses(a, b);
return a;
}
diff --git a/src/main/java/com/android/tools/r8/utils/WorkList.java b/src/main/java/com/android/tools/r8/utils/WorkList.java
index e9bf6cd..2e74be4 100644
--- a/src/main/java/com/android/tools/r8/utils/WorkList.java
+++ b/src/main/java/com/android/tools/r8/utils/WorkList.java
@@ -76,6 +76,10 @@
return !workingList.isEmpty();
}
+ public boolean isEmpty() {
+ return !hasNext();
+ }
+
public void markAsSeen(T item) {
seen.add(item);
}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/ImmutableInt2ReferenceSortedMap.java b/src/main/java/com/android/tools/r8/utils/collections/ImmutableInt2ReferenceSortedMap.java
new file mode 100644
index 0000000..af41bf1
--- /dev/null
+++ b/src/main/java/com/android/tools/r8/utils/collections/ImmutableInt2ReferenceSortedMap.java
@@ -0,0 +1,190 @@
+// 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.utils.collections;
+
+import com.android.tools.r8.errors.Unreachable;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceAVLTreeMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMap;
+import it.unimi.dsi.fastutil.ints.Int2ReferenceSortedMaps;
+import it.unimi.dsi.fastutil.ints.IntSortedSet;
+import it.unimi.dsi.fastutil.objects.ObjectSortedSet;
+import java.util.Map;
+import java.util.function.BiFunction;
+import java.util.function.Function;
+import org.jetbrains.annotations.Nullable;
+
+public class ImmutableInt2ReferenceSortedMap<V> extends Int2ReferenceSortedMaps.EmptySortedMap<V> {
+
+ private final Int2ReferenceSortedMap<V> sortedMap;
+
+ private ImmutableInt2ReferenceSortedMap(Int2ReferenceSortedMap<V> sortedMap) {
+ this.sortedMap = sortedMap;
+ }
+
+ public static <V> ImmutableInt2ReferenceSortedMap<V> of(Int2ReferenceSortedMap<V> sortedMap) {
+ return new ImmutableInt2ReferenceSortedMap<>(sortedMap);
+ }
+
+ public static <V> ImmutableInt2ReferenceSortedMap<V> of(int[] keys, V[] values) {
+ return new ImmutableInt2ReferenceSortedMap<>(new Int2ReferenceAVLTreeMap<>(keys, values));
+ }
+
+ public static <V> Builder<V> builder() {
+ return new Builder<>();
+ }
+
+ public static class Builder<V> {
+
+ private final Int2ReferenceSortedMap<V> sortedMap = new Int2ReferenceAVLTreeMap<>();
+
+ public Builder<V> put(int k, V v) {
+ sortedMap.put(k, v);
+ return this;
+ }
+
+ public ImmutableInt2ReferenceSortedMap<V> build() {
+ return new ImmutableInt2ReferenceSortedMap<>(sortedMap);
+ }
+ }
+
+ @Override
+ public int size() {
+ return sortedMap.size();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public ObjectSortedSet<Entry<V>> int2ReferenceEntrySet() {
+ return sortedMap.int2ReferenceEntrySet();
+ }
+
+ @Deprecated
+ @Override
+ @SuppressWarnings("unchecked")
+ public ObjectSortedSet<Map.Entry<Integer, V>> entrySet() {
+ return sortedMap.entrySet();
+ }
+
+ @Override
+ public IntSortedSet keySet() {
+ return sortedMap.keySet();
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Int2ReferenceSortedMap<V> subMap(final int from, final int to) {
+ return sortedMap.subMap(from, to);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Int2ReferenceSortedMap<V> headMap(final int to) {
+ return sortedMap.headMap(to);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public Int2ReferenceSortedMap<V> tailMap(final int from) {
+ return sortedMap.tailMap(from);
+ }
+
+ @Override
+ public boolean isEmpty() {
+ return sortedMap.isEmpty();
+ }
+
+ @Override
+ public int firstIntKey() {
+ return sortedMap.firstIntKey();
+ }
+
+ @Override
+ public int lastIntKey() {
+ return sortedMap.lastIntKey();
+ }
+
+ @Deprecated
+ @Override
+ public Int2ReferenceSortedMap<V> headMap(Integer oto) {
+ return sortedMap.headMap(oto);
+ }
+
+ @Deprecated
+ @Override
+ public Int2ReferenceSortedMap<V> tailMap(Integer ofrom) {
+ return sortedMap.tailMap(ofrom);
+ }
+
+ @Deprecated
+ @Override
+ public Int2ReferenceSortedMap<V> subMap(Integer ofrom, Integer oto) {
+ return sortedMap.subMap(ofrom, oto);
+ }
+
+ @Deprecated
+ @Override
+ public Integer firstKey() {
+ return sortedMap.firstKey();
+ }
+
+ @Deprecated
+ @Override
+ public Integer lastKey() {
+ return sortedMap.lastKey();
+ }
+
+ @Override
+ public V put(int key, V value) {
+ throw new Unreachable("Should not modify an immutable structure");
+ }
+
+ @Override
+ public V put(Integer ok, V ov) {
+ throw new Unreachable("Should not modify an immutable structure");
+ }
+
+ @Override
+ public void putAll(Map<? extends Integer, ? extends V> m) {
+ throw new Unreachable("Should not modify an immutable structure");
+ }
+
+ @Nullable
+ @Override
+ public V putIfAbsent(Integer key, V value) {
+ throw new Unreachable("Should not modify an immutable structure");
+ }
+
+ @Override
+ public V compute(
+ Integer key, BiFunction<? super Integer, ? super V, ? extends V> remappingFunction) {
+ throw new Unreachable("Should not modify an immutable structure");
+ }
+
+ @Override
+ public V computeIfAbsent(Integer key, Function<? super Integer, ? extends V> mappingFunction) {
+ throw new Unreachable("Should not modify an immutable structure");
+ }
+
+ @Override
+ public V computeIfPresent(
+ Integer key, BiFunction<? super Integer, ? super V, ? extends V> remappingFunction) {
+ throw new Unreachable("Should not modify an immutable structure");
+ }
+
+ @Override
+ public V remove(int key) {
+ throw new Unreachable("Should not modify an immutable structure");
+ }
+
+ @Override
+ public boolean remove(Object key, Object value) {
+ throw new Unreachable("Should not modify an immutable structure");
+ }
+
+ @Override
+ public V remove(Object ok) {
+ throw new Unreachable("Should not modify an immutable structure");
+ }
+}
diff --git a/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
index 92d51ea..0732bcb 100644
--- a/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
+++ b/src/main/java/com/android/tools/r8/utils/collections/ProgramMethodSet.java
@@ -15,6 +15,7 @@
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Set;
+import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
@@ -50,6 +51,10 @@
return new ProgramMethodSet(new LinkedHashMap<>());
}
+ public static ProgramMethodSet createSorted() {
+ return new ProgramMethodSet(new TreeMap<>(DexMethod::slowCompareTo));
+ }
+
public static ProgramMethodSet empty() {
return EMPTY;
}
diff --git a/src/test/java/com/android/tools/r8/TestBase.java b/src/test/java/com/android/tools/r8/TestBase.java
index 9aa9789..342920c 100644
--- a/src/test/java/com/android/tools/r8/TestBase.java
+++ b/src/test/java/com/android/tools/r8/TestBase.java
@@ -44,6 +44,7 @@
import com.android.tools.r8.references.TypeReference;
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.ProguardClassFilter;
import com.android.tools.r8.shaking.ProguardClassNameList;
import com.android.tools.r8.shaking.ProguardConfiguration;
@@ -650,7 +651,8 @@
protected static AppInfoWithClassHierarchy computeAppInfoWithClassHierarchy(AndroidApp app)
throws Exception {
return AppInfoWithClassHierarchy.createInitialAppInfoWithClassHierarchy(
- readApplicationForDexOutput(app, new InternalOptions()));
+ readApplicationForDexOutput(app, new InternalOptions()),
+ MainDexClasses.createEmptyMainDexClasses());
}
protected static AppView<AppInfoWithClassHierarchy> computeAppViewWithSubtyping(AndroidApp app)
@@ -1601,6 +1603,10 @@
return AndroidApiLevel.O;
}
+ public static AndroidApiLevel apiLevelWithNativeMultiDexSupport() {
+ return AndroidApiLevel.L;
+ }
+
public Path compileToZip(
TestParameters parameters, Collection<Class<?>> classPath, Class<?>... compilationUnit)
throws Exception {
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java
index 226af98..b2e1d59 100644
--- a/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorForwardingTest.java
@@ -5,14 +5,21 @@
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.readsInstanceField;
+import static com.android.tools.r8.utils.codeinspector.Matchers.writesInstanceField;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.core.IsNot.not;
import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
import com.android.tools.r8.TestParameters;
import com.android.tools.r8.classmerging.horizontal.ConstructorMergingTest.A;
import com.android.tools.r8.classmerging.horizontal.ConstructorMergingTest.B;
import com.android.tools.r8.classmerging.horizontal.ConstructorMergingTest.Main;
+import com.android.tools.r8.horizontalclassmerging.ClassMerger;
+import com.android.tools.r8.utils.codeinspector.ClassSubject;
+import com.android.tools.r8.utils.codeinspector.FieldSubject;
+import com.android.tools.r8.utils.codeinspector.MethodSubject;
import org.junit.Test;
public class MergedConstructorForwardingTest extends HorizontalClassMergingTestBase {
@@ -29,15 +36,37 @@
.addKeepMainRule(Main.class)
.addOptionsModification(
options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .enableInliningAnnotations()
.enableNeverClassInliningAnnotations()
.setMinApi(parameters.getApiLevel())
.run(parameters.getRuntime(), Main.class)
- .assertSuccessWithOutputLines("42", "13", "21", "39")
+ .assertSuccessWithOutputLines("42", "13", "21", "39", "print a", "print b")
.inspect(
codeInspector -> {
if (enableHorizontalClassMerging) {
- assertThat(codeInspector.clazz(A.class), isPresent());
+ ClassSubject aClassSubject = codeInspector.clazz(A.class);
+ assertThat(aClassSubject, isPresent());
+ FieldSubject classIdFieldSubject =
+ aClassSubject.uniqueFieldWithName(ClassMerger.CLASS_ID_FIELD_NAME);
+ assertThat(classIdFieldSubject, isPresent());
+
+ MethodSubject firstInitSubject = aClassSubject.init("int");
+ assertThat(firstInitSubject, isPresent());
+ assertThat(
+ firstInitSubject, writesInstanceField(classIdFieldSubject.getFieldReference()));
+
+ MethodSubject otherInitSubject = aClassSubject.init("long", "int");
+ assertThat(otherInitSubject, isPresent());
+ assertThat(
+ otherInitSubject, writesInstanceField(classIdFieldSubject.getFieldReference()));
+
+ MethodSubject printSubject = aClassSubject.method("void", "print");
+ assertThat(printSubject, isPresent());
+ assertThat(
+ printSubject, readsInstanceField(classIdFieldSubject.getFieldReference()));
+
assertThat(codeInspector.clazz(B.class), not(isPresent()));
+
// TODO(b/165517236): Explicitly check classes have been merged.
} else {
assertThat(codeInspector.clazz(A.class), isPresent());
@@ -55,6 +84,11 @@
public A(long x) {
System.out.println(x);
}
+
+ @NeverInline
+ public void print() {
+ System.out.println("print a");
+ }
}
@NeverClassInline
@@ -66,6 +100,11 @@
public B(long y) {
System.out.println(y * 3);
}
+
+ @NeverInline
+ public void print() {
+ System.out.println("print b");
+ }
}
public static class Main {
@@ -74,6 +113,8 @@
a = new A(13);
B b = new B();
b = new B(13);
+ a.print();
+ b.print();
}
}
}
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
new file mode 100644
index 0000000..1f0daeb
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/MergedConstructorStackTraceTest.java
@@ -0,0 +1,105 @@
+// 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.naming.retrace.StackTrace.isSame;
+import static com.android.tools.r8.utils.codeinspector.Matchers.isPresent;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestRuntime.CfRuntime;
+import com.android.tools.r8.naming.retrace.StackTrace;
+import com.android.tools.r8.naming.retrace.StackTrace.StackTraceLine;
+import org.junit.Before;
+import org.junit.Test;
+
+public class MergedConstructorStackTraceTest extends HorizontalClassMergingTestBase {
+
+ public StackTrace expectedStackTrace;
+
+ public MergedConstructorStackTraceTest(
+ TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Before
+ public void setup() throws Exception {
+ // Get the expected stack trace by running on the JVM.
+ expectedStackTrace =
+ testForJvm()
+ .addTestClasspath()
+ .run(CfRuntime.getSystemRuntime(), Main.class)
+ .assertFailure()
+ .map(StackTrace::extractFromJvm);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ .addKeepMainRule(Main.class)
+ .addKeepAttributeLineNumberTable()
+ .addKeepAttributeSourceFile()
+ .addOptionsModification(
+ options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .enableMergeAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .run(parameters.getRuntime(), Main.class)
+ .inspectStackTrace(
+ (stackTrace, codeInspector) -> {
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ if (enableHorizontalClassMerging) {
+ StackTrace expectedStackTraceWithMergedConstructor =
+ StackTrace.builder()
+ .add(expectedStackTrace)
+ .add(
+ 2,
+ StackTraceLine.builder()
+ .setClassName(A.class.getTypeName())
+ .setMethodName("<init>")
+ .setFileName(getClass().getSimpleName() + ".java")
+ .setLineNumber(0)
+ .build())
+ .build();
+ assertThat(stackTrace, isSame(expectedStackTraceWithMergedConstructor));
+ assertThat(codeInspector.clazz(B.class), not(isPresent()));
+ } else {
+ assertThat(stackTrace, isSame(expectedStackTrace));
+ assertThat(codeInspector.clazz(B.class), isPresent());
+ }
+ });
+ }
+
+ @NeverMerge
+ static class Parent {
+ Parent() {
+ if (System.currentTimeMillis() >= 0) {
+ throw new RuntimeException();
+ }
+ }
+ }
+
+ @NeverClassInline
+ static class A extends Parent {
+ A() {}
+ }
+
+ @NeverClassInline
+ static class B extends Parent {
+ B() {}
+ }
+
+ static class Main {
+ public static void main(String[] args) {
+ new A();
+ new B();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java
new file mode 100644
index 0000000..119913b
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/SuperConstructorCallsVirtualMethodTest.java
@@ -0,0 +1,94 @@
+// 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.NeverInline;
+import com.android.tools.r8.TestParameters;
+import org.junit.Test;
+
+public class SuperConstructorCallsVirtualMethodTest extends HorizontalClassMergingTestBase {
+ public SuperConstructorCallsVirtualMethodTest(
+ 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)
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("5", "foo hello", "B", "bar world", "5", "B")
+ .inspect(
+ codeInspector -> {
+ if (enableHorizontalClassMerging) {
+ assertThat(codeInspector.clazz(Parent.class), isPresent());
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(codeInspector.clazz(B.class), not(isPresent()));
+ // TODO(b/165517236): Explicitly check classes have been merged.
+ } else {
+ assertThat(codeInspector.clazz(Parent.class), isPresent());
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(codeInspector.clazz(B.class), isPresent());
+ }
+ });
+ }
+
+ @NeverClassInline
+ public static class Parent {
+ String field;
+
+ public Parent(String v) {
+ this.field = v;
+ print();
+ }
+
+ @NeverInline
+ public void print() {
+ System.out.println(field);
+ }
+ }
+
+ @NeverClassInline
+ public static class A extends Parent {
+ public A(String arg) {
+ super(arg);
+ System.out.println("foo " + arg);
+ }
+
+ @NeverInline
+ @Override
+ public void print() {
+ System.out.println(5);
+ }
+ }
+
+ @NeverClassInline
+ public static class B extends Parent {
+ public B(String arg) {
+ super("B");
+ System.out.println("bar " + arg);
+ }
+ }
+
+ public static class Main {
+ public static void main(String[] args) {
+ A a = new A("hello");
+ B b = new B("world");
+ a.print();
+ b.print();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodOverrideParentCollisionTest.java b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodOverrideParentCollisionTest.java
new file mode 100644
index 0000000..e304a70
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodOverrideParentCollisionTest.java
@@ -0,0 +1,92 @@
+// 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.horizontalclassmerging;
+
+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.NeverInline;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.classmerging.horizontal.HorizontalClassMergingTestBase;
+import org.junit.Test;
+
+public class VirtualMethodOverrideParentCollisionTest extends HorizontalClassMergingTestBase {
+
+ public VirtualMethodOverrideParentCollisionTest(
+ TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(this.getClass())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("foo", "bar", "foo", "parent")
+ .inspect(
+ codeInspector -> {
+ if (enableHorizontalClassMerging) {
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(codeInspector.clazz(B.class), not(isPresent()));
+ // TODO(b/165517236): Explicitly check classes have been merged.
+ } else {
+ assertThat(codeInspector.clazz(A.class), isPresent());
+ assertThat(codeInspector.clazz(B.class), isPresent());
+ }
+ });
+ }
+
+ @NeverClassInline
+ public static class Parent {
+ @NeverInline
+ public void foo() {
+ System.out.println("parent");
+ }
+ }
+
+ @NeverClassInline
+ public static class A extends Parent {
+ @NeverInline
+ @Override
+ public void foo() {
+ System.out.println("foo");
+ }
+ }
+
+ @NeverClassInline
+ public static class B extends Parent {
+ // TODO(b/164924717): remove non overlapping constructor requirement
+ public B(String s) {}
+
+ @NeverInline
+ public void bar() {
+ System.out.println("bar");
+ }
+ }
+
+ public static class Main {
+ @NeverInline
+ static void callFoo(Parent p) {
+ p.foo();
+ }
+
+ public static void main(String[] args) {
+ A a = new A();
+ a.foo();
+ B b = new B("");
+ b.bar();
+ callFoo(a);
+ callFoo(b);
+ }
+ }
+}
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
new file mode 100644
index 0000000..f323ec7
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/classmerging/horizontal/VirtualMethodSuperMerged.java
@@ -0,0 +1,100 @@
+// 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.NeverInline;
+import com.android.tools.r8.NeverMerge;
+import com.android.tools.r8.TestParameters;
+import org.junit.Test;
+
+public class VirtualMethodSuperMerged extends HorizontalClassMergingTestBase {
+ public VirtualMethodSuperMerged(TestParameters parameters, boolean enableHorizontalClassMerging) {
+ super(parameters, enableHorizontalClassMerging);
+ }
+
+ @Test
+ public void testR8() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(this.getClass())
+ .addKeepMainRule(Main.class)
+ .addOptionsModification(
+ options -> options.enableHorizontalClassMerging = enableHorizontalClassMerging)
+ .enableInliningAnnotations()
+ .enableNeverClassInliningAnnotations()
+ .enableMergeAnnotations()
+ .setMinApi(parameters.getApiLevel())
+ .run(parameters.getRuntime(), Main.class)
+ .assertSuccessWithOutputLines("foo", "parent b", "parent b", "x", "parent b")
+ .inspect(
+ codeInspector -> {
+ if (enableHorizontalClassMerging) {
+ assertThat(codeInspector.clazz(ParentA.class), isPresent());
+ assertThat(codeInspector.clazz(ParentB.class), not(isPresent()));
+ assertThat(codeInspector.clazz(X.class), isPresent());
+ assertThat(codeInspector.clazz(Y.class), not(isPresent()));
+ // TODO(b/165517236): Explicitly check classes have been merged.
+ } else {
+ assertThat(codeInspector.clazz(ParentA.class), isPresent());
+ assertThat(codeInspector.clazz(ParentB.class), isPresent());
+ assertThat(codeInspector.clazz(X.class), isPresent());
+ assertThat(codeInspector.clazz(Y.class), isPresent());
+ }
+ });
+ }
+
+ @NeverClassInline
+ public static class ParentA {
+ @NeverInline
+ void foo() {
+ System.out.println("foo");
+ }
+ }
+
+ @NeverMerge
+ @NeverClassInline
+ public static class ParentB {
+ @NeverInline
+ void print() {
+ System.out.println("parent b");
+ }
+ }
+
+ @NeverClassInline
+ public static class X extends ParentB {
+ public X() {
+ print();
+ }
+
+ @NeverInline
+ @Override
+ void print() {
+ super.print();
+ System.out.println("x");
+ }
+ }
+
+ @NeverClassInline
+ public static class Y extends ParentB {
+ public Y() {
+ print();
+ }
+ }
+
+ public static class Main {
+ public static void main(String[] args) {
+ ParentA a = new ParentA();
+ a.foo();
+ ParentB b = new ParentB();
+ b.print();
+ X x = new X();
+ Y y = new Y();
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
index db4d3df..fa6e974 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/JavaTimeTest.java
@@ -171,7 +171,7 @@
ToolHelper.runL8(l8Builder.build());
// Run on the JVM with desuagred library on classpath.
- TestRunResult result =
+ TestRunResult<?> result =
testForJvm()
.addProgramFiles(jar)
.addRunClasspathFiles(desugaredLib)
diff --git a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
index 2b84919..0245f6e 100644
--- a/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
+++ b/src/test/java/com/android/tools/r8/desugar/desugaredlibrary/MergingJ$Test.java
@@ -4,35 +4,82 @@
package com.android.tools.r8.desugar.desugaredlibrary;
+import static com.android.tools.r8.DiagnosticsMatcher.diagnosticType;
import static junit.framework.TestCase.assertNotNull;
import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.fail;
+import com.android.tools.r8.CompilationFailedException;
+import com.android.tools.r8.D8Command;
+import com.android.tools.r8.DexFileMergerHelper;
import com.android.tools.r8.L8;
import com.android.tools.r8.L8Command;
import com.android.tools.r8.OutputMode;
import com.android.tools.r8.StringResource;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.ToolHelper;
import com.android.tools.r8.desugar.desugaredlibrary.jdktests.Jdk11DesugaredLibraryTestBase;
+import com.android.tools.r8.errors.DuplicateTypesDiagnostic;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableMap;
import java.nio.file.Path;
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 MergingJ$Test extends Jdk11DesugaredLibraryTestBase {
+ @Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withNoneRuntime().build();
+ }
+
+ public MergingJ$Test(TestParameters parameters) {
+ parameters.assertNoneRuntime();
+ }
+
@Test
public void testMergingJ$() throws Exception {
Path mergerInputPart1 = buildSplitDesugaredLibraryPart1();
Path mergerInputPart2 = buildSplitDesugaredLibraryPart2();
- CodeInspector codeInspectorOutput = null;
+ assertThrows(
+ CompilationFailedException.class,
+ () ->
+ testForD8()
+ .addProgramFiles(mergerInputPart1, mergerInputPart2)
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .compileWithExpectedDiagnostics(
+ diagnostics -> {
+ diagnostics
+ .assertOnlyErrors()
+ .assertErrorsMatch(diagnosticType(DuplicateTypesDiagnostic.class));
+ }));
+ }
+
+ @Test
+ public void testMergingJ$WithDexFileMergerHelper() throws Exception {
+ Path mergerInputPart1 = buildSplitDesugaredLibraryPart1();
+ Path mergerInputPart2 = buildSplitDesugaredLibraryPart2();
+ Path merged = temp.newFolder().toPath().resolve("merged.jar");
+ D8Command command =
+ D8Command.builder()
+ .addProgramFiles(mergerInputPart1, mergerInputPart2)
+ .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
+ .setOutput(merged, OutputMode.DexIndexed)
+ .build();
try {
- codeInspectorOutput =
- testForD8()
- .addProgramFiles(mergerInputPart1, mergerInputPart2)
- .addLibraryFiles(ToolHelper.getAndroidJar(AndroidApiLevel.P))
- .compile()
- .inspector();
+ DexFileMergerHelper.run(
+ command,
+ true,
+ ImmutableMap.<String, Integer>builder()
+ .put(mergerInputPart1.toString(), 1)
+ .put(mergerInputPart2.toString(), 2)
+ .build());
} catch (Exception e) {
if (e.getCause().getMessage().contains("Merging dex file containing classes with prefix")) {
// TODO(b/138278440): Forbid to merge j$ classes in a Google3 compliant way.
@@ -44,6 +91,7 @@
}
throw e;
}
+ CodeInspector codeInspectorOutput = new CodeInspector(merged);
CodeInspector codeInspectorSplit1 = new CodeInspector(mergerInputPart1);
CodeInspector codeInspectorSplit2 = new CodeInspector(mergerInputPart2);
assertNotNull(codeInspectorOutput);
diff --git a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
index eeedbab..b48e0a93 100644
--- a/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
+++ b/src/test/java/com/android/tools/r8/dex/DebugByteCodeWriterTest.java
@@ -3,11 +3,13 @@
// BSD-style license that can be found in the LICENSE file.
package com.android.tools.r8.dex;
+import com.android.tools.r8.graph.AppInfo;
import com.android.tools.r8.graph.DexApplication;
import com.android.tools.r8.graph.DexDebugEvent;
import com.android.tools.r8.graph.DexDebugInfo;
import com.android.tools.r8.graph.DexItemFactory;
import com.android.tools.r8.graph.DexString;
+import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
import com.android.tools.r8.graph.ObjectToOffsetMapping;
import com.android.tools.r8.naming.NamingLens;
@@ -21,8 +23,10 @@
private ObjectToOffsetMapping emptyObjectTObjectMapping() {
return new ObjectToOffsetMapping(
- DexApplication.builder(new InternalOptions(new DexItemFactory(), new Reporter()), null)
- .build(),
+ AppInfo.createInitialAppInfo(
+ DexApplication.builder(new InternalOptions(new DexItemFactory(), new Reporter()), null)
+ .build()),
+ GraphLens.getIdentityLens(),
NamingLens.getIdentityLens(),
InitClassLens.getDefault(),
Collections.emptyList(),
diff --git a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
index 5cb94de..b567056 100644
--- a/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
+++ b/src/test/java/com/android/tools/r8/dex/SharedClassWritingTest.java
@@ -27,6 +27,7 @@
import com.android.tools.r8.graph.DirectMappedDexApplication;
import com.android.tools.r8.graph.GraphLens;
import com.android.tools.r8.graph.InitClassLens;
+import com.android.tools.r8.graph.LazyLoadedDexApplication;
import com.android.tools.r8.graph.MethodAccessFlags;
import com.android.tools.r8.graph.ParameterAnnotationsList;
import com.android.tools.r8.naming.NamingLens;
@@ -144,8 +145,9 @@
DexProgramClass sharedSynthesizedClass =
makeClass(options, "SharedSynthesized", 100, Constants.MAX_NON_JUMBO_INDEX - 1, classes);
- DexApplication.Builder builder = DirectMappedDexApplication.builder(options, Timing.empty());
- builder.addSynthesizedClass(sharedSynthesizedClass, false);
+ LazyLoadedDexApplication.Builder builder =
+ DirectMappedDexApplication.builder(options, Timing.empty());
+ builder.addSynthesizedClass(sharedSynthesizedClass);
classes.forEach(builder::addProgramClass);
DexApplication application = builder.build();
@@ -153,9 +155,7 @@
options.programConsumer = consumer;
ApplicationWriter writer =
new ApplicationWriter(
- application,
AppView.createForD8(AppInfo.createInitialAppInfo(application)),
- options,
null,
GraphLens.getIdentityLens(),
InitClassLens.getDefault(),
diff --git a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
index f503359..0ef3bdf 100644
--- a/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
+++ b/src/test/java/com/android/tools/r8/dexsplitter/DexSplitterTests.java
@@ -369,7 +369,7 @@
// Ensure that the Class1 is actually in the correct split. Note that Class2 would have been
// shaken away.
- CodeInspector inspector = new CodeInspector(base, proguardMap.toString());
+ CodeInspector inspector = new CodeInspector(base, proguardMap);
ClassSubject subject = inspector.clazz("dexsplitsample.Class1");
assertTrue(subject.isPresent());
assertTrue(subject.isRenamed());
diff --git a/src/test/java/com/android/tools/r8/enumunboxing/StringValueOfEnumUnboxingTest.java b/src/test/java/com/android/tools/r8/enumunboxing/StringValueOfEnumUnboxingTest.java
new file mode 100644
index 0000000..1ab86b3
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/enumunboxing/StringValueOfEnumUnboxingTest.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.enumunboxing;
+
+import com.android.tools.r8.NeverClassInline;
+import com.android.tools.r8.NeverInline;
+import com.android.tools.r8.R8TestRunResult;
+import com.android.tools.r8.TestParameters;
+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 StringValueOfEnumUnboxingTest extends EnumUnboxingTestBase {
+ private final TestParameters parameters;
+ private final boolean enumValueOptimization;
+ private final EnumKeepRules enumKeepRules;
+
+ @Parameters(name = "{0} valueOpt: {1} keep: {2}")
+ public static List<Object[]> data() {
+ return enumUnboxingTestParameters();
+ }
+
+ public StringValueOfEnumUnboxingTest(
+ TestParameters parameters, boolean enumValueOptimization, EnumKeepRules enumKeepRules) {
+ this.parameters = parameters;
+ this.enumValueOptimization = enumValueOptimization;
+ this.enumKeepRules = enumKeepRules;
+ }
+
+ @Test
+ public void testEnumUnboxing() throws Exception {
+ Class<?> classToTest = Main.class;
+ R8TestRunResult run =
+ testForR8(parameters.getBackend())
+ .addProgramClasses(classToTest, MyEnum.class)
+ .addKeepMainRule(classToTest)
+ .addKeepRules(enumKeepRules.getKeepRules())
+ .enableNeverClassInliningAnnotations()
+ .enableInliningAnnotations()
+ .addOptionsModification(opt -> enableEnumOptions(opt, enumValueOptimization))
+ .allowDiagnosticInfoMessages()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspectDiagnosticMessages(
+ m -> assertEnumIsUnboxed(MyEnum.class, classToTest.getSimpleName(), m))
+ .run(parameters.getRuntime(), classToTest)
+ .assertSuccess();
+ assertLines2By2Correct(run.getStdOut());
+ }
+
+ @NeverClassInline
+ enum MyEnum {
+ A,
+ B,
+ C
+ }
+
+ static class Main {
+ public static void main(String[] args) {
+ System.out.println(MyEnum.A.ordinal());
+ System.out.println(0);
+ System.out.println(getString(MyEnum.A));
+ System.out.println("A");
+ System.out.println(getString(null));
+ System.out.println("null");
+ }
+
+ @NeverInline
+ private static String getString(MyEnum e) {
+ return String.valueOf(e);
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/internal/D8PhotosVerificationTest.java b/src/test/java/com/android/tools/r8/internal/D8PhotosVerificationTest.java
deleted file mode 100644
index 4094bb7..0000000
--- a/src/test/java/com/android/tools/r8/internal/D8PhotosVerificationTest.java
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright (c) 2017, the R8 project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-package com.android.tools.r8.internal;
-
-import com.android.tools.r8.CompilationFailedException;
-import com.android.tools.r8.CompilationMode;
-import com.android.tools.r8.R8RunArtTestsTest.CompilerUnderTest;
-import java.io.IOException;
-import java.util.concurrent.ExecutionException;
-import org.junit.Test;
-
-public class D8PhotosVerificationTest extends CompilationTestBase {
- public static final String PHOTOS =
- "third_party/photos/2017-06-06/PhotosEnglishOnlyLegacy_proguard.jar";
-
- public void runD8AndCheckVerification(CompilationMode mode, String version)
- throws ExecutionException, IOException, CompilationFailedException {
- runAndCheckVerification(CompilerUnderTest.D8, mode, version, null, version);
- }
-
- @Test
- public void verify() throws Exception {
- runD8AndCheckVerification(CompilationMode.RELEASE, PHOTOS);
- }
-}
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1419TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1419TreeShakeJarVerificationTest.java
index 97b4db0..bbddb47 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeV1419TreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1419TreeShakeJarVerificationTest.java
@@ -69,8 +69,7 @@
new ProtoApplicationStats(dexItemFactory, compileResult.inspector(), original);
ProtoApplicationStats baseline =
new ProtoApplicationStats(
- dexItemFactory,
- new CodeInspector(getReleaseApk(), getReleaseProguardMap().toString()));
+ dexItemFactory, new CodeInspector(getReleaseApk(), getReleaseProguardMap()));
System.out.println(actual.getStats(baseline));
}
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1444TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1444TreeShakeJarVerificationTest.java
index b2498b5..0a304b1 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeV1444TreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1444TreeShakeJarVerificationTest.java
@@ -78,8 +78,7 @@
new ProtoApplicationStats(dexItemFactory, compileResult.inspector(), original);
ProtoApplicationStats baseline =
new ProtoApplicationStats(
- dexItemFactory,
- new CodeInspector(getReleaseApk(), getReleaseProguardMap().toString()));
+ dexItemFactory, new CodeInspector(getReleaseApk(), getReleaseProguardMap()));
System.out.println(actual.getStats(baseline));
}
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1508TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1508TreeShakeJarVerificationTest.java
index b48bec3..79e7eb1 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeV1508TreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1508TreeShakeJarVerificationTest.java
@@ -78,8 +78,7 @@
new ProtoApplicationStats(dexItemFactory, compileResult.inspector(), original);
ProtoApplicationStats baseline =
new ProtoApplicationStats(
- dexItemFactory,
- new CodeInspector(getReleaseApk(), getReleaseProguardMap().toString()));
+ dexItemFactory, new CodeInspector(getReleaseApk(), getReleaseProguardMap()));
System.out.println(actual.getStats(baseline));
}
diff --git a/src/test/java/com/android/tools/r8/internal/YouTubeV1533TreeShakeJarVerificationTest.java b/src/test/java/com/android/tools/r8/internal/YouTubeV1533TreeShakeJarVerificationTest.java
index 632210e..09293ac 100644
--- a/src/test/java/com/android/tools/r8/internal/YouTubeV1533TreeShakeJarVerificationTest.java
+++ b/src/test/java/com/android/tools/r8/internal/YouTubeV1533TreeShakeJarVerificationTest.java
@@ -78,8 +78,7 @@
new ProtoApplicationStats(dexItemFactory, compileResult.inspector(), original);
ProtoApplicationStats baseline =
new ProtoApplicationStats(
- dexItemFactory,
- new CodeInspector(getReleaseApk(), getReleaseProguardMap().toString()));
+ dexItemFactory, new CodeInspector(getReleaseApk(), getReleaseProguardMap()));
System.out.println(actual.getStats(baseline));
}
diff --git a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
index b351ca2..1d7686c 100644
--- a/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
+++ b/src/test/java/com/android/tools/r8/ir/IrInjectionTestBase.java
@@ -14,7 +14,7 @@
import com.android.tools.r8.ir.code.InstructionListIterator;
import com.android.tools.r8.ir.code.NumberGenerator;
import com.android.tools.r8.ir.conversion.IRConverter;
-import com.android.tools.r8.shaking.MainDexClasses;
+import com.android.tools.r8.shaking.MainDexTracingResult;
import com.android.tools.r8.smali.SmaliBuilder;
import com.android.tools.r8.smali.SmaliBuilder.MethodSignature;
import com.android.tools.r8.smali.SmaliTestBase;
@@ -113,7 +113,7 @@
public String run() throws IOException {
Timing timing = Timing.empty();
- IRConverter converter = new IRConverter(appView, timing, null, MainDexClasses.NONE);
+ IRConverter converter = new IRConverter(appView, timing, null, MainDexTracingResult.NONE);
converter.replaceCodeForTesting(method, code);
AndroidApp app = writeDex();
return runOnArtRaw(app, DEFAULT_MAIN_CLASS_NAME).stdout;
diff --git a/src/test/java/com/android/tools/r8/ir/optimize/typechecks/InstanceOfMethodSpecializationTest.java b/src/test/java/com/android/tools/r8/ir/optimize/typechecks/InstanceOfMethodSpecializationTest.java
new file mode 100644
index 0000000..5d13f66
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/ir/optimize/typechecks/InstanceOfMethodSpecializationTest.java
@@ -0,0 +1,181 @@
+// 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.typechecks;
+
+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.Assume.assumeTrue;
+
+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 com.google.common.collect.ImmutableList;
+import java.util.List;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+@RunWith(Parameterized.class)
+public class InstanceOfMethodSpecializationTest extends TestBase {
+
+ private static final List<String> EXPECTED =
+ ImmutableList.of(
+ "true", "false", "false", "true", "false", "true", "true", "false", "false", "true",
+ "true", "false", "true", "false", "true");
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters().withAllRuntimesAndApiLevels().build();
+ }
+
+ public InstanceOfMethodSpecializationTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void testJvm() throws Exception {
+ assumeTrue(parameters.isCfRuntime());
+ testForJvm()
+ .addTestClasspath()
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(InstanceOfMethodSpecializationTest.class)
+ .addKeepMainRule(TestClass.class)
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .inspect(this::inspect)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines(EXPECTED);
+ }
+
+ private void inspect(CodeInspector inspector) {
+ ClassSubject aClassSubject = inspector.clazz(A.class);
+ assertThat(aClassSubject, isPresent());
+ assertThat(aClassSubject.uniqueMethodWithName("isA"), not(isPresent()));
+ assertThat(aClassSubject.uniqueMethodWithName("isB"), not(isPresent()));
+ assertThat(aClassSubject.uniqueMethodWithName("isC"), not(isPresent()));
+ assertThat(aClassSubject.uniqueMethodWithName("isSuper"), isPresent());
+ assertThat(aClassSubject.uniqueMethodWithName("isSub"), isPresent());
+
+ ClassSubject bClassSubject = inspector.clazz(B.class);
+ assertThat(bClassSubject, isPresent());
+ assertThat(bClassSubject.uniqueMethodWithName("isA"), not(isPresent()));
+ assertThat(bClassSubject.uniqueMethodWithName("isB"), not(isPresent()));
+ assertThat(bClassSubject.uniqueMethodWithName("isC"), not(isPresent()));
+ assertThat(bClassSubject.uniqueMethodWithName("isSuper"), not(isPresent()));
+ assertThat(bClassSubject.uniqueMethodWithName("isSub"), not(isPresent()));
+
+ ClassSubject cClassSubject = inspector.clazz(C.class);
+ assertThat(cClassSubject, isPresent());
+ assertThat(cClassSubject.uniqueMethodWithName("isA"), not(isPresent()));
+ assertThat(cClassSubject.uniqueMethodWithName("isB"), not(isPresent()));
+ assertThat(cClassSubject.uniqueMethodWithName("isC"), not(isPresent()));
+ assertThat(cClassSubject.uniqueMethodWithName("isSuper"), isPresent());
+ assertThat(cClassSubject.uniqueMethodWithName("isSub"), isPresent());
+ }
+
+ public static class TestClass {
+
+ public static void main(String[] args) {
+ A a = System.currentTimeMillis() > 0 ? new A() : new B();
+ A b = System.currentTimeMillis() > 0 ? new B() : new A();
+ A c = System.currentTimeMillis() > 0 ? new C() : new A();
+ System.out.println(a.isA());
+ System.out.println(a.isB());
+ System.out.println(a.isC());
+ System.out.println(a.isSuper());
+ System.out.println(a.isSub());
+ System.out.println(b.isA());
+ System.out.println(b.isB());
+ System.out.println(b.isC());
+ System.out.println(b.isSuper());
+ System.out.println(b.isSub());
+ System.out.println(c.isA());
+ System.out.println(c.isB());
+ System.out.println(c.isC());
+ System.out.println(c.isSuper());
+ System.out.println(c.isSub());
+ }
+ }
+
+ public static class A {
+
+ boolean isA() {
+ return true;
+ }
+
+ boolean isB() {
+ return false;
+ }
+
+ boolean isC() {
+ return false;
+ }
+
+ boolean isSuper() {
+ return true;
+ }
+
+ boolean isSub() {
+ return false;
+ }
+ }
+
+ public static class B extends A {
+
+ @Override
+ boolean isA() {
+ return true;
+ }
+
+ @Override
+ boolean isB() {
+ return true;
+ }
+
+ @Override
+ boolean isSuper() {
+ return false;
+ }
+
+ @Override
+ boolean isSub() {
+ return true;
+ }
+ }
+
+ public static class C extends A {
+
+ @Override
+ boolean isA() {
+ return true;
+ }
+
+ @Override
+ boolean isC() {
+ return true;
+ }
+
+ @Override
+ boolean isSuper() {
+ return false;
+ }
+
+ @Override
+ boolean isSub() {
+ return true;
+ }
+ }
+}
diff --git a/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java b/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
index 08a4ae9..0d96a65 100644
--- a/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
+++ b/src/test/java/com/android/tools/r8/jsr45/JSR45Tests.java
@@ -162,10 +162,10 @@
annotationElement[0].value.asDexValueString().value.toSourceString());
}
- private String getGeneratedProguardMap() throws IOException {
+ private Path getGeneratedProguardMap() throws IOException {
Path mapFile = Paths.get(tmpOutputDir.getRoot().getCanonicalPath(), DEFAULT_MAP_FILENAME);
if (Files.exists(mapFile)) {
- return mapFile.toAbsolutePath().toString();
+ return mapFile.toAbsolutePath();
}
return null;
}
diff --git a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
index fdc2ab9..37d2899 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/MainDexListTests.java
@@ -71,7 +71,7 @@
import com.android.tools.r8.utils.FileUtils;
import com.android.tools.r8.utils.InternalOptions;
import com.android.tools.r8.utils.ListUtils;
-import com.android.tools.r8.utils.MainDexList;
+import com.android.tools.r8.utils.MainDexListParser;
import com.android.tools.r8.utils.Reporter;
import com.android.tools.r8.utils.StringUtils;
import com.android.tools.r8.utils.ThreadUtils;
@@ -182,7 +182,7 @@
}
private static Set<DexType> parse(Path path, DexItemFactory itemFactory) throws IOException {
- return MainDexList.parseList(StringResource.fromFile(path), itemFactory);
+ return MainDexListParser.parseList(StringResource.fromFile(path), itemFactory);
}
@Rule
@@ -331,9 +331,11 @@
@Test
public void singleEntryNoNewLine() throws Exception {
DexItemFactory factory = new DexItemFactory();
- Set<DexType> types = MainDexList.parseList(
- StringResource.fromString("desugaringwithmissingclasstest1/Main.class", Origin.unknown()),
- factory);
+ Set<DexType> types =
+ MainDexListParser.parseList(
+ StringResource.fromString(
+ "desugaringwithmissingclasstest1/Main.class", Origin.unknown()),
+ factory);
assertEquals(1, types.size());
assertEquals(
"Ldesugaringwithmissingclasstest1/Main;",
@@ -350,7 +352,7 @@
for (String entry : lines) {
DexType type = factory.createType("L" + entry.replace(".class", "") + ";");
assertTrue(types.contains(type));
- assertSame(type, MainDexList.parseEntry(entry, factory));
+ assertSame(type, MainDexListParser.parseEntry(entry, factory));
}
}
@@ -866,9 +868,7 @@
DirectMappedDexApplication application = builder.build().toDirect();
ApplicationWriter writer =
new ApplicationWriter(
- application,
AppView.createForD8(AppInfo.createInitialAppInfo(application)),
- options,
null,
GraphLens.getIdentityLens(),
InitClassLens.getDefault(),
diff --git a/src/test/java/com/android/tools/r8/maindexlist/warnings/MainDexWarningsTest.java b/src/test/java/com/android/tools/r8/maindexlist/warnings/MainDexWarningsTest.java
index bf33b1c..4f5e54a 100644
--- a/src/test/java/com/android/tools/r8/maindexlist/warnings/MainDexWarningsTest.java
+++ b/src/test/java/com/android/tools/r8/maindexlist/warnings/MainDexWarningsTest.java
@@ -10,17 +10,39 @@
import com.android.tools.r8.ForceInline;
import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.TestParametersCollection;
import com.android.tools.r8.utils.AndroidApiLevel;
import com.android.tools.r8.utils.codeinspector.CodeInspector;
import com.google.common.collect.ImmutableList;
import java.util.List;
import org.hamcrest.CoreMatchers;
import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+@RunWith(Parameterized.class)
public class MainDexWarningsTest extends TestBase {
- private List<Class<?>> testClasses = ImmutableList.of(Main.class, Static.class, Static2.class);
- private Class<?> mainClass = Main.class;
+ private static final List<Class<?>> testClasses =
+ ImmutableList.of(Main.class, Static.class, Static2.class);
+ private static final List<Class<?>> testClassesWithoutStatic =
+ ImmutableList.of(Main.class, Static2.class);
+ private static final Class<?> mainClass = Main.class;
+
+ private final TestParameters parameters;
+
+ @Parameterized.Parameters(name = "{0}")
+ public static TestParametersCollection data() {
+ return getTestParameters()
+ .withDexRuntimes()
+ .withApiLevelsEndingAtExcluding(apiLevelWithNativeMultiDexSupport())
+ .build();
+ }
+
+ public MainDexWarningsTest(TestParameters parameters) {
+ this.parameters = parameters;
+ }
private void classStaticGone(CodeInspector inspector) {
assertThat(inspector.clazz(Static.class), CoreMatchers.not(isPresent()));
@@ -29,12 +51,13 @@
@Test
public void testNoWarningFromMainDexRules() throws Exception {
- testForR8(Backend.DEX)
+ testForR8(parameters.getBackend())
.setMinApi(AndroidApiLevel.K)
.addProgramClasses(testClasses)
.addKeepMainRule(mainClass)
// Include main dex rule for class Static.
.addMainDexClassRules(Main.class, Static.class)
+ .setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::classStaticGone)
.assertNoMessages();
@@ -42,13 +65,14 @@
@Test
public void testWarningFromManualMainDexList() throws Exception {
- testForR8(Backend.DEX)
+ testForR8(parameters.getBackend())
.setMinApi(AndroidApiLevel.K)
- .addProgramClasses(testClasses)
+ .addProgramClasses(testClassesWithoutStatic)
.addKeepMainRule(mainClass)
// Include explicit main dex entry for class Static.
.addMainDexListClasses(Static.class)
.allowDiagnosticWarningMessages()
+ .setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::classStaticGone)
.assertOnlyWarnings()
@@ -59,15 +83,16 @@
@Test
public void testWarningFromManualMainDexListWithRuleAsWell() throws Exception {
- testForR8(Backend.DEX)
+ testForR8(parameters.getBackend())
.setMinApi(AndroidApiLevel.K)
- .addProgramClasses(testClasses)
+ .addProgramClasses(testClassesWithoutStatic)
.addKeepMainRule(mainClass)
// Include explicit main dex entry for class Static.
.addMainDexListClasses(Main.class, Static.class)
// Include main dex rule for class Static2.
.addMainDexClassRules(Static2.class)
.allowDiagnosticWarningMessages()
+ .setMinApi(parameters.getApiLevel())
.compile()
.inspect(this::classStaticGone)
.assertOnlyWarnings()
diff --git a/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java b/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
index 0c4f597..0da2866 100644
--- a/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
+++ b/src/test/java/com/android/tools/r8/naming/retrace/StackTrace.java
@@ -33,11 +33,21 @@
private Builder() {}
+ public Builder add(StackTrace stackTrace) {
+ stackTraceLines.addAll(stackTrace.getStackTraceLines());
+ return this;
+ }
+
public Builder add(StackTraceLine line) {
stackTraceLines.add(line);
return this;
}
+ public Builder add(int i, StackTraceLine line) {
+ stackTraceLines.add(i, line);
+ return this;
+ }
+
public Builder addWithoutFileNameAndLineNumber(Class<?> clazz, String methodName) {
return addWithoutFileNameAndLineNumber(clazz.getTypeName(), methodName);
}
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 47157aa..1639c79 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageAfterCollisionWithPackagePrivateSignatureTest.java
@@ -47,7 +47,6 @@
@Test
public void testR8() throws Exception {
- assumeTrue(parameters.isCfRuntime());
testForR8(parameters.getBackend())
.addInnerClasses(RepackageAfterCollisionWithPackagePrivateSignatureTest.class)
.addKeepClassAndMembersRules(TestClass.class)
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 69a88d0..c656981 100644
--- a/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageTest.java
@@ -109,7 +109,6 @@
@Test
public void testR8() throws Exception {
- assumeTrue(!enableExperimentalRepackaging || parameters.isCfRuntime());
testForR8(parameters.getBackend())
.addProgramFiles(ToolHelper.getClassFilesForTestPackage(TestClass.class.getPackage()))
.addKeepMainRule(TestClass.class)
diff --git a/src/test/java/com/android/tools/r8/repackage/RepackageWithMainDexListTest.java b/src/test/java/com/android/tools/r8/repackage/RepackageWithMainDexListTest.java
new file mode 100644
index 0000000..00dd079
--- /dev/null
+++ b/src/test/java/com/android/tools/r8/repackage/RepackageWithMainDexListTest.java
@@ -0,0 +1,104 @@
+// 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.assertFalse;
+
+import com.android.tools.r8.OutputMode;
+import com.android.tools.r8.R8TestCompileResult;
+import com.android.tools.r8.TestBase;
+import com.android.tools.r8.TestParameters;
+import com.android.tools.r8.utils.codeinspector.CodeInspector;
+import com.google.common.collect.ImmutableList;
+import java.nio.file.Path;
+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 RepackageWithMainDexListTest 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()
+ .withApiLevelsEndingAtExcluding(apiLevelWithNativeMultiDexSupport())
+ .build());
+ }
+
+ public RepackageWithMainDexListTest(
+ String flattenPackageHierarchyOrRepackageClasses, TestParameters parameters) {
+ this.flattenPackageHierarchyOrRepackageClasses = flattenPackageHierarchyOrRepackageClasses;
+ this.parameters = parameters;
+ }
+
+ @Test
+ public void test() throws Exception {
+ testForR8(parameters.getBackend())
+ .addInnerClasses(getClass())
+ // -keep,allowobfuscation does not prohibit repackaging.
+ .addKeepClassRulesWithAllowObfuscation(TestClass.class, OtherTestClass.class)
+ .addKeepRules(
+ "-keepclassmembers class " + TestClass.class.getTypeName() + " { <methods>; }")
+ .addKeepRules(
+ "-" + flattenPackageHierarchyOrRepackageClasses + " \"" + REPACKAGE_DIR + "\"")
+ // Add a class that will be repackaged to the main dex list.
+ .addMainDexListClasses(TestClass.class)
+ .addOptionsModification(
+ options -> {
+ assertFalse(options.testing.enableExperimentalRepackaging);
+ options.testing.enableExperimentalRepackaging = true;
+ })
+ // Debug mode to enable minimal main dex.
+ .debug()
+ .setMinApi(parameters.getApiLevel())
+ .compile()
+ .apply(this::checkCompileResult)
+ .run(parameters.getRuntime(), TestClass.class)
+ .assertSuccessWithOutputLines("Hello world!");
+ }
+
+ private void checkCompileResult(R8TestCompileResult compileResult) throws Exception {
+ Path out = temp.newFolder().toPath();
+ compileResult.app.writeToDirectory(out, OutputMode.DexIndexed);
+ Path classes = out.resolve("classes.dex");
+ Path classes2 = out.resolve("classes2.dex");
+ inspectMainDex(new CodeInspector(classes, compileResult.getProguardMap()));
+ inspectSecondaryDex(new CodeInspector(classes2, compileResult.getProguardMap()));
+ }
+
+ private void inspectMainDex(CodeInspector inspector) {
+ assertThat(inspector.clazz(TestClass.class), isPresent());
+ assertThat(inspector.clazz(OtherTestClass.class), not(isPresent()));